diff --git a/Dashboard/app/assets/images/openMASTER.png b/Dashboard/app/assets/images/openMASTER.png index 187abdc..436ce91 100644 Binary files a/Dashboard/app/assets/images/openMASTER.png and b/Dashboard/app/assets/images/openMASTER.png differ diff --git a/Dashboard/app/assets/images/openMASTER_nobg.png b/Dashboard/app/assets/images/openMASTER_nobg.png index e54c671..2840568 100644 Binary files a/Dashboard/app/assets/images/openMASTER_nobg.png and b/Dashboard/app/assets/images/openMASTER_nobg.png differ diff --git "a/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/data/input/Data_Industrial.xlsx b/data/input/Data_Industrial.xlsx index 6c16429..d8bc9b5 100644 --- a/data/input/Data_Industrial.xlsx +++ b/data/input/Data_Industrial.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:453ebf662c132fc75ff1e45f0bab9847e7da232a1ac4271c9217274162df8d8d -size 152531 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/data/input/JUST_openMASTER_Data.xlsx b/data/input/JUST_openMASTER_Data.xlsx new file mode 100644 index 0000000..e8390f2 --- /dev/null +++ b/data/input/JUST_openMASTER_Data.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:28014884f8a6590da30277546aef124b158d852ff0075014119dea0105906f54 +size 3797499 diff --git a/data/input/costs_correl.csv b/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/data/input/costs_correl_orig.csv b/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/data/input/covar.xlsx b/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/data/input/input_om.xlsx b/data/input/input_om.xlsx new file mode 100644 index 0000000..e421a3f --- /dev/null +++ b/data/input/input_om.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ef2b7a10bae5f1a3b46d7c80e1abe8eccb48b66c328fb2f3f793f9230da7a49b +size 5275392 diff --git a/data/input/input_om_v1.xlsx b/data/input/input_om_v1.xlsx new file mode 100644 index 0000000..40d3c37 --- /dev/null +++ b/data/input/input_om_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d075be551f995913e4a8448272896bf22a456f5c543fd5fd5144fc7d7cdeb1af +size 5266242 diff --git a/data/input/input_om_v2.xlsx b/data/input/input_om_v2.xlsx new file mode 100644 index 0000000..7324006 --- /dev/null +++ b/data/input/input_om_v2.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8bfb3f3761452d69597e0fcad83ba57d25475eb14fda8d9d81388f39aa6a89f9 +size 5118055 diff --git a/data/input/mean.csv b/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/data/input/openMASTER_Data.xlsx b/data/input/openMASTER_Data.xlsx deleted file mode 100644 index a3b5d04..0000000 --- a/data/input/openMASTER_Data.xlsx +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c8587c7592ede1dcdca4b5bdb6547d1e2478f74a9722159f63639780129f9966 -size 1117974 diff --git a/data/input/openMASTER_Data_2050.xlsx b/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..d994269 --- /dev/null +++ b/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:41b64705c3c520cc242a7309c9fa507c7f0db7ef968afc1959934a6f002e68f9 +size 1371133 diff --git a/data/input/openMASTER_Data_2070.xlsx b/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/data/input/openMASTER_Data_ResMod.xlsm b/data/input/openMASTER_Data_ResMod.xlsm new file mode 100644 index 0000000..6a21bd9 --- /dev/null +++ b/data/input/openMASTER_Data_ResMod.xlsm @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:89eb2c94c26123d85b40e89f0143afab44c0839ccc5824cba34917bf4cd297af +size 3876198 diff --git a/data/input/openMASTER_Data_ResMod_CCAA.xlsm b/data/input/openMASTER_Data_ResMod_CCAA.xlsm new file mode 100644 index 0000000..dc8e67b --- /dev/null +++ b/data/input/openMASTER_Data_ResMod_CCAA.xlsm @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:09683acbc81eab9c5474faa3a8376ffb0eff648709fe98fb2f723b9c561b06ec +size 5347161 diff --git a/data/input/openMASTER_Data.xlsm b/data/input/openMASTER_Data__.xlsm similarity index 100% rename from data/input/openMASTER_Data.xlsm rename to data/input/openMASTER_Data__.xlsm diff --git a/docs/openMASTER_ResMOD_Doc.pdf b/docs/openMASTER_ResMOD_Doc.pdf new file mode 100644 index 0000000..20f8e0b Binary files /dev/null and b/docs/openMASTER_ResMOD_Doc.pdf differ diff --git a/docs/openMASTER_arch.vsdx b/docs/openMASTER_arch.vsdx index 835f6eb..345e438 100644 Binary files a/docs/openMASTER_arch.vsdx and b/docs/openMASTER_arch.vsdx differ diff --git a/notebooks/Results_FastAnalysis.ipynb b/notebooks/Results_FastAnalysis.ipynb new file mode 100644 index 0000000..0caf873 --- /dev/null +++ b/notebooks/Results_FastAnalysis.ipynb @@ -0,0 +1,4732 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# This code will be used to analyze the output data from a scenario of the openMASTER model\n", + "\n", + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "import os\n", + "\n", + "def read_csv_files(path):\n", + " # Dictionary to store DataFrames\n", + " dataframes = {}\n", + "\n", + " # List all CSV files in the provided directory\n", + " for file in os.listdir(path):\n", + " if file.endswith('.csv'):\n", + " # Create a DataFrame and store it in the dictionary\n", + " file_path = os.path.join(path, file) # Full path to file\n", + " df_name = file[:-4] # Remove .csv from filename to use as dictionary key\n", + " dataframes[df_name] = pd.read_csv(file_path)\n", + "\n", + " return dataframes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load data results and input parameters" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "data_results = read_csv_files('../scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/tmp/output/')\n", + "data_input = read_csv_files('../scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/tmp/input/')\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Final energy consumption per sector for the calibration year" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Total_GWh_Households_TEST: 168829.2250326372\n", + "Total_GWh_Industry: 231552.63130958058\n", + "Total_GWh_Transport: 220575.60689743026\n", + "Total_GWh_Services: 87412.87107867762\n", + "Energy Service Not Served for the calibration year: 0.0\n" + ] + } + ], + "source": [ + "# Total Consumption by Sector\n", + "# Show all the rows in the df data_results['vQES'] that include in the column sES the value 'sES_DSOTH_RES' at the begining of the string and that the value in sYear is y2020\n", + "#Total_GWh_Households_ESSD = data_results['vQES'][(data_results['vQES'].sES.str.startswith('sES_DSOTH_RES')) & (data_results['vQES'].sYear=='y2020')].vQES.sum() # Calibracion en ES consumido por SDMD\n", + "# Total Consumption by Sector\n", + "# Show all the rows in the df data_results['vQES'] that include in the column sES the value 'sES_DSOTH_RES' at the beginning of the string and that the value in sYear is y2020\n", + "#Total_GWh_Households_ESSD = data_results['vQES'][(data_results['vQES'].sES.str.startswith('sES_DSOTH_RES')) & (data_results['vQES'].sYear=='y2020')].vQES.sum() # Calibracion en ES consumido por SDMD\n", + "Total_GWh_Households_TEST = data_results['vQSTInTE'].loc[\n", + " (data_results['vQSTInTE'].sYear == 'y2020') & \n", + " (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES')), \n", + " 'vQSTInTE'\n", + "].sum()\n", + "\n", + "Total_GWh_Industry = data_results['vQSTInTE'].loc[\n", + " (data_results['vQSTInTE'].sYear == 'y2020') & \n", + " (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND')), \n", + " 'vQSTInTE'\n", + "].sum()\n", + "\n", + "Total_GWh_Transport = data_results['vQSTInTE'].loc[\n", + " (data_results['vQSTInTE'].sYear == 'y2020') & \n", + " (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA')), \n", + " 'vQSTInTE'\n", + "].sum()\n", + "\n", + "Total_GWh_Services = data_results['vQES'][\n", + " (data_results['vQES'].sES.str.startswith('sES_DSOTH_SRV')) & \n", + " (data_results['vQES'].sYear == 'y2020')\n", + "].vQES.sum()\n", + "\n", + "ES_NS = data_results['vQESNS'][(data_results['vQESNS'].sYear == 'y2020')].vQESNS.sum()\n", + "\n", + "#print(f\"Total_GWh_Households_ESSD: {Total_GWh_Households_ESSD }\")\n", + "print(f\"Total_GWh_Households_TEST: {Total_GWh_Households_TEST }\")\n", + "print(f\"Total_GWh_Industry: {Total_GWh_Industry }\")\n", + "print(f\"Total_GWh_Transport: {Total_GWh_Transport }\")\n", + "print(f\"Total_GWh_Services: {Total_GWh_Services }\")\n", + "print(f\"Energy Service Not Served for the calibration year: {ES_NS}\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Primary energy consumption by sector at the entire time window" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA28AAAImCAYAAADE77LsAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAADE10lEQVR4nOzdd3iTVRvH8e+TNOnepQPKpmWPFspG2VsUxD0RFAUn+oqK4l6vGwFx4EJ5VUBFFARRUUH23nvT0r3SNut53j/Shoa2UKBtWnp/rourzbNykoY2v5xz7qNomqYhhBBCCCGEEKJa07m7AUIIIYQQQgghzk/CmxBCCCGEEELUABLehBBCCCGEEKIGkPAmhBBCCCGEEDWAhDchhBBCCCGEqAEkvAkhhBBCCCFEDSDhTQghhBBCCCFqAAlvQgghhBBCCFEDSHgTQogaSNM0dzdBXKbktVUx5HkUQlQGD3c3QAghaoMnnniCH3744ZzHdO7cmTlz5pzzmOzsbF566SWuu+46EhISLuj+161bxx9//FHmMc2bNz/nNe6++24ee+yxct9ndXb48GG++OILVq5cSXJyMiEhIcTHx3PPPffQokULdzfPLZKSkpg6dSpTp04lOjoagL59+9K5c2dee+21Sr//5s2bc//99/PAAw9U+LVPnjzJzJkzWblyJWlpafj5+dGhQwfuuusuOnfuXOH3N3PmTIxGI+PGjavwawshajcJb0IIUQUmTJjAjTfe6Lw9c+ZMdu3axfTp053b/Pz8znud3bt3s3DhQq699tpKaefo0aO57rrrSt0XERFRKfdZ1ZYtW8bjjz9OTEwM9913H9HR0SQlJfHFF19w/fXX88EHH9CjRw93N7PK/fvvv/z1118u26ZPn16u12V1lpKSwg033EBERASTJk0iKiqK9PR05s2bxx133MF7773HwIEDK/Q+33vvPe6///4KvaYQQoCENyGEqBINGjSgQYMGztshISEYjUY6dOjgvkaVIjIystq1qSIdO3aMyZMn06tXL9599130er1z38CBA7npppuYPHkyf/zxB0aj0Y0trR5atWrl7iZcsu+++47s7Gx+/fVXlyA6YMAArrvuukoJb0IIUVlkzpsQQlQjq1at4uabb6Zjx4506dKFRx99lMTERADWrl3L7bffDsDtt9/ObbfdBoDdbuejjz5i+PDhtGvXjg4dOnDjjTeyZs2aSmnjiRMnaN68OUuWLOHBBx8kLi6Ozp078/TTT5OXl+dy7Lx58xg2bBht2rShd+/evP/++9jtduf+J554gjvuuINnn32W+Ph4hg4dit1uJzc3l6lTp9KtWzfi4uJ45JFH+Pzzz51DO7/++muaN2/O4cOHXe5v4cKFtGzZ0vmcnW3OnDlYLBaefvppl+AG4O3tzeTJk7n22mvJyspybl+8eDGjRo0iLi6OHj16MHXqVJf977//PgMGDGDFihVcddVVtGnThkGDBvHjjz+6XP+LL75g8ODBtG3bll69evHcc8+Rm5vr8px+//33Luc88cQT9O3b13n7tttuY+rUqcycOZNevXrRvn177r77blJTU1mwYAEDBgwgLi6OO++8kxMnTric98QTTzBr1iy6d+9Ox44dmTBhAidPngTg+++/58knnwSgX79+PPHEE4Bj2GTR9wA5OTm8+uqr9O/fn7Zt2zJ8+HDmz5/v0ua+ffsybdo0Xn/9dbp37067du0YO3YsR44cKfVnUlxubi6PPfYYcXFxdOvWjZdeeon8/Hzg4n/mqampKIri8roD0Ov1PProo9xwww0u2zds2MCtt95K+/bt6dy5M5MnTyY9Pd3lmEOHDnH//ffTuXNnEhISGD9+PAcPHgTODD+ePn26y1Dk7du3M3bsWLp06UJ8fDz33nsv+/fvd+5fu3YtzZs355tvvqFPnz7Ex8ezatWq8z5nQojaRcKbEEJUEz/++CN33XUXUVFRvP322zz55JNs3ryZG264gbS0NFq3bs3UqVMBmDp1Ks8++ywAb775JjNnzuSGG27gk08+4cUXXyQzM5OHHnrI+ca3vFRVxWazlfrvbM8++yz16tVj5syZjB07lvnz5/PBBx8493/44Yc888wzdOvWjVmzZnHLLbfw8ccf88wzz7hcZ8OGDSQmJjJjxgweffRR9Ho9EyZMYMmSJTzwwAO88847mEwm3nrrLec5V111FZ6enixcuLDEc9itWzeioqJKfXz//PMPrVq1KnMIaLdu3XjkkUeoU6cO4BjeOmnSJDp06MC0adOYOHEiS5cu5bbbbqOgoMB5XkpKCi+88AK33347H330EdHR0UyePNn5hv7nn3/mjTfe4JZbbmH27NlMnDiRhQsX8uKLL57rx1Gqn3/+mdWrV/Pyyy8zZcoUVq9eza233sqXX37J5MmTeeGFF9i6dSsvvPCCy3m///4733//PU8//TTPP/88u3fv5rbbbiM/P5/evXtz3333AY7QMWHChBL3W1BQwM0338yiRYsYN24cM2fOpGPHjkyZMoVZs2a5HPvll19y6NAhXn31VV566SV27NjB5MmTz/vY5syZg8lk4t1332X8+PHMmzfPOc/yYn/mvXv3pqCggOuvv57Zs2eza9cuZ5Dr0aOH8wMRgPXr13PnnXfi5eXFu+++y1NPPcW6deu4/fbbnT/v06dPc8MNN3DkyBGee+453njjDVJTU7njjjvIzMzk22+/BRxDkIu+X7NmDTfddBMAr7zyCi+99BKJiYnceOONztdIkenTpzN58mSmTp1KXFzceZ8zIUQtowkhhKhykydP1vr06eO8bbfbtR49emh33XWXy3FHjx7VWrdurb3++uuapmnamjVrtNjYWG3NmjXOYyZNmqR9/vnnLuctXbpUi42N1TZv3lzq/ZUmNjb2nP/S0tI0TdO048ePa7Gxsdpjjz3mcv5tt92mDR8+XNM0TcvOztbatWunTZ061eWY7777TouNjdX27dvnbFdsbKyWmJjoPObff//VYmNjtaVLl7o8P0OGDNFiY2NdHnefPn00VVU1TdO0xMRErUWLFtqiRYvKfIzt27fXHn744XM+D0UyMzO1Nm3aaM8884zL9vXr12uxsbHaV199pWmapk2bNk2LjY3V/v33X+cxJ0+e1GJjY7XZs2drmqZpzzzzjDZo0CDNbrc7j1m4cKH25Zdfapp25jldsGCBy32d/XO79dZbtbZt22qZmZnObWPHjtViY2O1Y8eOObe98MILWseOHV3Oa926tcsxO3fu1GJjY7W5c+dqmqZpCxYs0GJjY7Xjx487j+nTp482efJkTdM07euvv9ZiY2O1TZs2ubTxqaee0tq2batlZGQ4z+nTp49ms9mcx7z//vtabGyslp6erpUlNjZWGz58uMtz9Pnnn2uxsbHa3r17NU27uJ+5pmnaV199pcXHxztfy/Hx8drEiRO1lStXuhx3ww03aMOHD3dp+6FDh7SWLVs6f96vvfaa1q5dOy05Odl5TGJiota7d29txYoVzscybdo05/7Ro0drQ4cOdbluVlaW1rlzZ+3BBx/UNO3M/+0ZM2ac87EIIWo36XkTQohq4PDhw6SkpDB8+HCX7Q0a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w4ezfft2pk2bxujRo116by/0Z/70009z2223MWrUKG6//XZatmyJqqqsX7+ezz//nBtvvJFmzZoBMGnSJO655x7n/0G73c6nn37K1q1bnRU477zzTn788UfGjRvH+PHjMRgMfPDBB0RGRnLVVVc5n8tNmzaxfv16OnXqxKOPPsrYsWO55557uPnmm7FarXz00UdYLBZnqBdCiPKQ8CaEENXEqFGj8PX15cMPP2TixIn4+fnRq1cvJk2a5BziFxMTw/Dhw/n666/5559/+Pnnn5k5cyb//e9/eeihh/D19aVly5Z89dVX3H333WzYsMFlnbDzKSpOUpoWLVqUKNN+Lg8//DB16tRh7ty5fPLJJwQGBtKtWzcmTZrkDKFleeedd3jttdd46623sNls9OvXj5tuuqnE2mngKAW/evVqrr766nK1a+TIkTRs2JAvvviCd999l7S0NOrUqUN8fDzvv/++S2h54IEHCAsL46uvvuLbb78lKCiIwYMH8/DDD19QqLrxxhuxWq188803zJ07Fy8vL7p168Z//vMfDAYDAK+99hovvvgiTz/9NH5+fowePZqOHTsyb968ct/PuXTq1ImuXbsyZcoUwLEe2+OPP+5cjLxLly50796dt956i9WrV/PRRx+5nO/t7c2cOXN46623nKG8SZMmvPzyy4wePbpC2jhx4kR27NjBvffei7+/P+PGjeP+++8vcdyF/MzbtGnDjz/+yIcffshXX31FSkoKer2eZs2a8dRTT7m0vWfPnsyePZvp06fz4IMPYjAYaN26NZ999pmzIE1UVBRz587ljTfe4IknnsBoNNKlSxfeeecd51Dbe++9l5kzZ3L33XezePFiunXrxmeffca0adOYNGkSRqORTp068frrrxMTE1Mhz50QonZQtAudzS6EEEJUopMnT7Jlyxb69euHl5eXc/uDDz7I8ePH+eGHH1yOHzduHJ6ensyYMaOqm1pjFFW1nDNnjptbUjHkZy6EqK2k500IIUS1otPpeOKJJ+jXrx+jR49Gr9fzzz//sGzZMl599VXncTNmzODw4cOsXLmSuXPnurHFoqrIz1wIUdtJeBNCCFGtREVF8fHHHzNjxgwefvhhbDYbTZs25c0333RZc+2PP/7g2LFjPP744xdUPETUXPIzF0LUdjJsUgghhBBCCCFqAFkqQAghhBBCCCFqAAlv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AABYAOENAAAAACyA8AYAAAAAFkB4AwAAAAALILwBAAAAgAUQ3gAAAADAAghvAAAAAGABhDcAAAAAsADCGwAAAABYAOENAAAAACyA8AYAAAAAFkB4AwAAAAALILwBAAAAgAUQ3gAAAADAAghvAAAAAGABhDcAAAAAsADCGwAAAABYAOENAAAAACyA8AYAAAAAFkB4AwAAAAALILwBAAAAgAUQ3gAAAADAAghvAAAAAGABhDcAAAAAsADCGwAAAABYAOENAAAAACyA8AYAAAAAFkB4AwAAAAALILwBAAAAgAUQ3gAAAADAAghvAAAAAGABhDcAAAAAsADCGwAAAABYAOENAAAAACyA8AYAAAAAFkB4AwAAAAALILwBAAAAgAUQ3gAAAADAAghvAAAAAGABhDcAAAAAsADCGwAAAABYAOENAAAAACygV4W33/zmN7r88ssjln311VeaO3euJk2apFmzZun3v/99xPpgMKinnnpKJ598siZNmqRrr71WO3bs6PYyAAAAACCWek14e/nll/Xkk09GLKuqqtLVV1+tYcOGadmyZbr++uu1aNEiLVu2LLTNr3/9ay1dulQPPvigXn31VQWDQV1zzTXy+/3dWgYAAAAAxFJcTx/A7t27dd9996moqEgjRoyIWPfaa6/J6XRqwYIFiouLU35+vrZt26bFixdrzpw58vv9ev7553XrrbfqtNNOkyQ98cQTOvnkk/WXv/xFs2fP7pYyAAAAACDWerzl7csvv5TT6dRbb72l448/PmLd6tWrVVhYqLi49ox54oknauvWrdq7d682bNighoYGTZ8+PbQ+NTVV48eP16pVq7qtDAAAAACItR5veZs1a5ZmzZrV6bry8nIVFBRELBs0aJAkqaysTOXl5ZKkwYMHd9imbV13lDFw4MDDOFMAAAAAOHo93vJ2MF6vVy6XK2JZfHy8JMnn88nj8UhSp9v4fL5uKwMAAAAAYq1Xh7eEhITQoCFt2sJSYmKiEhISJKnTbdxud7eVAQAAAACx1qvDW05OjioqKiKWtf2cnZ0d6urY2TbZ2dndVgYAAAAAxFqvDm9Tp07VmjVrFAgEQss++eQTjRw5UgMGDNDYsWOVnJysoqKi0Pra2lqtX79eU6dO7bYyAAAAACDWenV4mzNnjurr63X33XeruLhYy5cv1wsvvKAf/ehHklqeU5s7d64W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AAAAAGABhDcAAAAAsADCGwAAAABYAOENAAAAACyA8AYAAAAAFkB4AwAAAAALILwBAAAAgAUQ3gAAAADAAghvAAAAAGABhLc+pLq6WvPnz9cpp5yiyZMn69JLL9Xq1atD6z/++GNdfPHFOv7443X22WfrnXfeidi/rKxMt9xyi2bMmKGpU6fqBz/4gTZv3hyxzXvvvadzzz1XEydO1IUXXqiPP/64W86tv+qOOj3zzDM1ZsyYiH933nlnt5xff9TVOt2+fbuuu+46TZkyRVOmTNEtt9yi3bt3R2xzqDIQfd1Rr1dffXWHa/Xyyy/vlvPrj7pap+FWr16tcePGqaioKGI512r364565VrtXl2t0zVr1nSorzFjxkTUa6+6Vg36jKuvvtrMnj3brFq1ypSUlJgHHnjATJw40WzZssUUFxeb4447zjz++OOmuLjYPPfcc2b8+PHmo48+MsYY4/P5zOzZs83cuXPN2rVrzaZNm8yNN95opk+fbvbt22eMMebjjz82EyZMMC+++KIpLi42jzzyiDn22GNNcXFxT552nxbrOm1oaDBjx441//znP01FRUXoX21tbU+edp/W1TqdOXOm+eEPf2g2btxo1q9fby677DJz4YUXmmAwaIwxhywDsRHrejXGmOnTp5ulS5dGXKtVVVU9dMZ9X1fqNFxtba2ZOXOmKSgoMJ988kloOddqz4h1vRrDtdrdulqnL7/8sjn99NMj6quiosL4fD5jTO+7VglvfcTWrVtNQUGBWb16dWhZMBg0p59+unnyySfNvffeay655JKIfW655RYzb948Y4wxK1asMAUFBaa8vDy03uv1muOPP968/vrrxhhj5s2bZ2666aaIMr773e+ae++9N0Zn1b91R51+/vnnpqCgwFRXV3fDGaGrdbp161bz05/+NBS+jTHmr3/9qykoKAgtO1QZiL7uqNe9e/eagoIC8+WXX3bDGaGrdbr/8iuuuKLDTT7XavfrjnrlWu1e0ajT++67z/z4xz8+4Gv0tmuVbpN9REZGhhYvXqzjjjsutMxms8lms6m2tlarV6/W9OnTI/Y58cQTtWbNGhljNHr0aC1evFjZ2dmh9XZ7y69HbW2tgsGg/vWvf3UoY9q0aVq1alUMz6z/inWdStLGjRs1cOBApaWldcMZoat1Onz4cP3qV79SZmamJKm0tFSvvPKKJkyY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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Use vectorized operations for filtering and summing\n", + "years = ['y2020', 'y2025', 'y2030', 'y2035', 'y2040', 'y2045', 'y2050']\n", + "households_mask = data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES')\n", + "industry_mask = data_results['vQSTInTE'].sST.str.startswith('sST_DSIND')\n", + "transport_mask = data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA')\n", + "services_mask = data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_SRV')\n", + "\n", + "Total_GWh_Households_TEST = {year: data_results['vQSTInTE'].loc[(data_results['vQSTInTE'].sYear == year) & households_mask, 'vQSTInTE'].sum() for year in years}\n", + "Total_GWh_Industry = {year: data_results['vQSTInTE'].loc[(data_results['vQSTInTE'].sYear == year) & industry_mask, 'vQSTInTE'].sum() for year in years}\n", + "Total_GWh_Transport = {year: data_results['vQSTInTE'].loc[(data_results['vQSTInTE'].sYear == year) & transport_mask, 'vQSTInTE'].sum() for year in years}\n", + "Total_GWh_Services = {year: data_results['vQSTInTE'].loc[(data_results['vQSTInTE'].sYear == year) & services_mask, 'vQSTInTE'].sum() for year in years}\n", + "\n", + "# Extract values for each year\n", + "Total_GWh_Households_TEST_2020 = Total_GWh_Households_TEST['y2020']\n", + "Total_GWh_Households_TEST_2025 = Total_GWh_Households_TEST['y2025']\n", + "Total_GWh_Households_TEST_2030 = Total_GWh_Households_TEST['y2030']\n", + "Total_GWh_Households_TEST_2035 = Total_GWh_Households_TEST['y2035']\n", + "Total_GWh_Households_TEST_2040 = Total_GWh_Households_TEST['y2040']\n", + "Total_GWh_Households_TEST_2045 = Total_GWh_Households_TEST['y2045']\n", + "Total_GWh_Households_TEST_2050 = Total_GWh_Households_TEST['y2050']\n", + "\n", + "# Extract values for each year using vectorized operations\n", + "Total_GWh_Industry_2020 = Total_GWh_Industry['y2020']\n", + "Total_GWh_Industry_2025 = Total_GWh_Industry['y2025']\n", + "Total_GWh_Industry_2030 = Total_GWh_Industry['y2030']\n", + "Total_GWh_Industry_2035 = Total_GWh_Industry['y2035']\n", + "Total_GWh_Industry_2040 = Total_GWh_Industry['y2040']\n", + "Total_GWh_Industry_2045 = Total_GWh_Industry['y2045']\n", + "Total_GWh_Industry_2050 = Total_GWh_Industry['y2050']\n", + "\n", + "Total_GWh_Transport_2020 = Total_GWh_Transport['y2020']\n", + "Total_GWh_Transport_2025 = Total_GWh_Transport['y2025']\n", + "Total_GWh_Transport_2030 = Total_GWh_Transport['y2030']\n", + "Total_GWh_Transport_2035 = Total_GWh_Transport['y2035']\n", + "Total_GWh_Transport_2040 = Total_GWh_Transport['y2040']\n", + "Total_GWh_Transport_2045 = Total_GWh_Transport['y2045']\n", + "Total_GWh_Transport_2050 = Total_GWh_Transport['y2050']\n", + "\n", + "Total_GWh_Services_2020 = Total_GWh_Services['y2020']\n", + "Total_GWh_Services_2025 = Total_GWh_Services['y2025']\n", + "Total_GWh_Services_2030 = Total_GWh_Services['y2030']\n", + "Total_GWh_Services_2035 = Total_GWh_Services['y2035']\n", + "Total_GWh_Services_2040 = Total_GWh_Services['y2040']\n", + "Total_GWh_Services_2045 = Total_GWh_Services['y2045']\n", + "Total_GWh_Services_2050 = Total_GWh_Services['y2050']\n", + "\n", + "# Plot the results\n", + "\n", + "# Create a DataFrame with the results\n", + "df = pd.DataFrame({\n", + " 'Sector': ['Households', 'Industry', 'Transport', 'Services'],\n", + " '2020': [Total_GWh_Households_TEST_2020, Total_GWh_Industry_2020, Total_GWh_Transport_2020, Total_GWh_Services_2020],\n", + " '2025': [Total_GWh_Households_TEST_2025, Total_GWh_Industry_2025, Total_GWh_Transport_2025, Total_GWh_Services_2025],\n", + " '2030': [Total_GWh_Households_TEST_2030, Total_GWh_Industry_2030, Total_GWh_Transport_2030, Total_GWh_Services_2030],\n", + " '2035': [Total_GWh_Households_TEST_2035, Total_GWh_Industry_2035, Total_GWh_Transport_2035, Total_GWh_Services_2035],\n", + " '2040': [Total_GWh_Households_TEST_2040, Total_GWh_Industry_2040, Total_GWh_Transport_2040, Total_GWh_Services_2040],\n", + " '2045': [Total_GWh_Households_TEST_2045, Total_GWh_Industry_2045, Total_GWh_Transport_2045, Total_GWh_Services_2045],\n", + " '2050': [Total_GWh_Households_TEST_2050, Total_GWh_Industry_2050, Total_GWh_Transport_2050, Total_GWh_Services_2050]\n", + "})\n", + "\n", + "# Melt the DataFrame to plot it\n", + "df_melted = df.melt(id_vars='Sector', var_name='Year', value_name='Total GWh')\n", + "df_melted['Year'] = df_melted['Year'].astype(int)\n", + "\n", + "# Plot the results\n", + "# sns.set_theme()\n", + "plt.figure(figsize=(10, 6))\n", + "sns.lineplot(data=df_melted, x='Year', y='Total GWh', hue='Sector', marker='o')\n", + "plt.title('Total Energy Consumption by Sector')\n", + "plt.ylabel('Total GWh')\n", + "plt.grid()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Shadow price of electricity" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjoAAAHVCAYAAAD4slEKAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAACBEUlEQVR4nO3dd3hTddsH8O/JajrZpWwQsGUVKFBG2fqgIqggypApe4jKEhUQUR55oYBgQYYMQREEBVRQUXxkCCJDAWXI3qVAC6Vtds77R5rThq6MkzY03891eVlOTu7caU6aO78piKIogoiIiKgYUhR1AkRERETewkKHiIiIii0WOkRERFRssdAhIiKiYouFDhERERVbLHSIiIio2GKhQ0RERMUWCx0iIiIqtljoEHmosNbc5NqeRESuY6FDD7XJkycjMjIyz//i4uKkczt27IjJkyfL+vhnzpxB7969Czzv66+/RmRkJK5evepU3AfPd/ZxPNWvXz/069fvoY0vt6tXryIyMhJff/211x9r27Zt6NChA+rXr49p06Z5/fF8gdFoxJIlS/Dkk0+iUaNGeOKJJ5CQkACj0ehw3vHjx9GvXz80btwYrVu3xrx583Kc888//2Do0KFo0aIFmjdvjpdffhn//POPwzlmsxkffvgh2rVrh4YNG6JPnz44evSo158nFS1VUSdA5Kly5cohISEh19vUarVXH/uHH37An3/+WeB57du3x4YNGxAeHu5U3AfPd/ZxSF7h4eHYsGEDqlat6vXHmjFjBqpXr45Zs2ahfPnyXn88X/D+++/jm2++wahRo9CgQQMcP34cixYtwvXr1/Hf//4XAHDlyhUMGjQIjRo1wocffohz585h/vz5uHv3LmbMmAEAuHTpEvr27Yv69etj5syZEAQBK1euRJ8+fbB582Y88sgjAIBZs2Zh06ZNGD9+PCpVqoRVq1Zh4MCB2LJlC6pVq1ZkvwfyLhY69NDTaDRo1KhRUaeRr9KlS6N06dJeO5+8ozCvrbt37yIuLg7NmzcvlMcraikpKfjyyy8xYcIEDBkyBADQsmVLAMDcuXMxYcIElC5dGsuXL0dwcDAWL14MjUaDdu3aQavV4r333sOIESNQsWJFrF27FoGBgVi6dCmCgoIAAC1atEDHjh3x2WefYdq0abhx4wa++OILvP322+jTpw8AoHXr1njiiSew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OL5t2zZYLBY0adIEgG28S2JiosM5hw8fLjD+n3/+iVatWuHYsWMQBAF16tTB66+/jkcffRTXr1/3KCdnKJVKp899MIezZ8+iTp06aNCgARo0aID69etj9erV+Omnn3K9T0BAABo3bowdO3Y4rMT8yy+/OJx3+PBh1KpVC88//7xU5Ny8eRP//vtvjllWPXr0wL59+/Ddd9+hc+fOOVp9iIgtOkSUj1q1aqFbt25YuHAhdDodmjVrhpMnTyIhIQHNmzeXBtN26NABv/zyCz744AN07NgRhw4dwpYtWwqMX7duXWi1WkyaNAmvvPIKypYti3379uHkyZPS1G93c3KGvZD49ddfUaJECURFRTl1v1GjRqFXr14YPnw4evfujYCAAGzYsAE///wzFi5cmOf9xo0bhwEDBmDMmDHo2bMnLly4gCVLljicEx0djcWLF2PZsmVo1KgRLl26hKVLl8JoNErjceyeeOIJvPfeezh27BimTp3q9PMm8icsdIgoXzNnzkS1atXw1VdfYfny5QgPD0f//v0xatQoaezK888/j8uXL2Pz5s1Yv349mjVrhoULF6J37975xg4ICMDKlSsxd+5czJw5E6mpqahevTpmzJiB7t27e5STM2rXro0uXbrg888/x549e/Ddd985db+oqCh8/vnnmD9/PiZNmgRRFPHoo49i0aJFeOyxx/K8X9OmTbF8+XLMmzcPY8aMQeXKlfHf//4XI0aMkM4ZPnw4UlJSsGbNGixatAgVKlTAs88+C0EQsHTpUqSmpiIsLAyA7ffXokULnD9/HtHR0U4/byJ/IojczY6I6KGk1+vRrl07jBo1CgMGDCjqdIh8Elt0iIgeMteuXcPmzZuxb98+CIKA559/vqhTIvJZLHSIiB4yCoUCa9euRXBwMObPny8tLEhEObHrioiIiIotTi8nIiKiYouFDhERERVbLHSIiIio2GKhQ0RERMUWCx0iIiIqtljoEBERUbHFQoeIiIiKLRY6REREVGyx0CEiIqJi6/8Ba1ciLUna6OwAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "duals_EQ_TEBalance = data_results['duals_EQ_TEBalance']\n", + "# Preserve the values of sTE in duals_EQ_TEBalance that are equal to sTEELECE\n", + "df_summer = duals_EQ_TEBalance[duals_EQ_TEBalance.sTE.str.startswith('sTEELEOTH') & (duals_EQ_TEBalance.sYear == 'y2020') & (duals_EQ_TEBalance.sSeason == 'R')]\n", + "df_spring = duals_EQ_TEBalance[duals_EQ_TEBalance.sTE.str.startswith('sTEELEOTH') & (duals_EQ_TEBalance.sYear == 'y2020') & (duals_EQ_TEBalance.sSeason == 'S')]\n", + "df_fall = duals_EQ_TEBalance[duals_EQ_TEBalance.sTE.str.startswith('sTEELEOTH') & (duals_EQ_TEBalance.sYear == 'y2020') & (duals_EQ_TEBalance.sSeason == 'F')]\n", + "df_winter = duals_EQ_TEBalance[duals_EQ_TEBalance.sTE.str.startswith('sTEELEOTH') & (duals_EQ_TEBalance.sYear == 'y2020') & (duals_EQ_TEBalance.sSeason == 'W')]\n", + "\n", + "plt.plot(df_summer.sHour, df_summer.dual_value*-1000)\n", + "plt.plot(df_spring.sHour, df_spring.dual_value*-1000)\n", + "plt.plot(df_fall.sHour, df_fall.dual_value*-1000)\n", + "# plt.plot(df_winter.sHour, df_winter.dual_value*-1000)\n", + "\n", + "plt.xticks(rotation=90)\n", + "\n", + "plt.ylabel('[€/kWh]')\n", + "plt.xlabel('Hours of the day')\n", + "plt.title('Electricity shadow price for year 2020')\n", + "plt.legend(['Summer', 'Spring', 'Autumn', 'Winter'])\n" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Total Consumption by Sector\n", + "y2020solpv=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESOLPV')) & (data_results['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025solpv=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESOLPV')) & (data_results['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030solpv=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESOLPV')) & (data_results['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035solpv=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESOLPV')) & (data_results['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040solpv=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESOLPV')) & (data_results['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045solpv=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESOLPV')) & (data_results['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050solpv=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESOLPV')) & (data_results['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020wind=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEWINON')) & (data_results['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025wind=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEWINON')) & (data_results['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030wind=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEWINON')) & (data_results['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035wind=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEWINON')) & (data_results['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040wind=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEWINON')) & (data_results['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045wind=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEWINON')) & (data_results['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050wind=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEWINON')) & (data_results['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020solth=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESOLTH')) & (data_results['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025solth=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESOLTH')) & (data_results['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030solth=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESOLTH')) & (data_results['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035solth=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESOLTH')) & (data_results['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040solth=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESOLTH')) & (data_results['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045solth=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESOLTH')) & (data_results['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050solth=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESOLTH')) & (data_results['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020solte=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESOLTE')) & (data_results['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025solte=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESOLTE')) & (data_results['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030solte=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESOLTE')) & (data_results['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035solte=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESOLTE')) & (data_results['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040solte=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESOLTE')) & (data_results['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045solte=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESOLTE')) & (data_results['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050solte=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESOLTE')) & (data_results['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020biomec=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOMEC')) & (data_results['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025biomec=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOMEC')) & (data_results['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030biomec=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOMEC')) & (data_results['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035biomec=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOMEC')) & (data_results['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040biomec=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOMEC')) & (data_results['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045biomec=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOMEC')) & (data_results['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050biomec=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOMEC')) & (data_results['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020biomaw=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOMAW')) & (data_results['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025biomaw=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOMAW')) & (data_results['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030biomaw=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOMAW')) & (data_results['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035biomaw=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOMAW')) & (data_results['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040biomaw=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOMAW')) & (data_results['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045biomaw=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOMAW')) & (data_results['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050biomaw=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOMAW')) & (data_results['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020biomfw=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOMFW')) & (data_results['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025biomfw=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOMFW')) & (data_results['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030biomfw=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOMFW')) & (data_results['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035biomfw=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOMFW')) & (data_results['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040biomfw=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOMFW')) & (data_results['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045biomfw=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOMFW')) & (data_results['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050biomfw=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOMFW')) & (data_results['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020swast=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESWAST')) & (data_results['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025swast=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESWAST')) & (data_results['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030swast=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESWAST')) & (data_results['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035swast=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESWAST')) & (data_results['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040swast=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESWAST')) & (data_results['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045swast=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESWAST')) & (data_results['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050swast=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPESWAST')) & (data_results['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020bioethpi=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOETHPI')) & (data_results['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025bioethpi=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOETHPI')) & (data_results['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030bioethpi=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOETHPI')) & (data_results['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035bioethpi=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOETHPI')) & (data_results['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040bioethpi=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOETHPI')) & (data_results['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045bioethpi=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOETHPI')) & (data_results['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050bioethpi=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOETHPI')) & (data_results['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020biodiepi=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIODIEPI')) & (data_results['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025biodiepi=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIODIEPI')) & (data_results['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030biodiepi=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIODIEPI')) & (data_results['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035biodiepi=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIODIEPI')) & (data_results['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040biodiepi=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIODIEPI')) & (data_results['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045biodiepi=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIODIEPI')) & (data_results['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050biodiepi=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIODIEPI')) & (data_results['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020biogas=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOGAS')) & (data_results['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025biogas=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOGAS')) & (data_results['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030biogas=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOGAS')) & (data_results['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035biogas=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOGAS')) & (data_results['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040biogas=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOGAS')) & (data_results['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045biogas=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOGAS')) & (data_results['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050biogas=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEBIOGAS')) & (data_results['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020hydro=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEHYDRR')) & (data_results['vQPEDom'].sYear=='y2020')].vQPEDom.sum() + data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEHYDRC')) & (data_results['vQPEDom'].sYear=='y2020')].vQPEDom.sum() + data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEMNHYDR')) & (data_results['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025hydro=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEHYDRR')) & (data_results['vQPEDom'].sYear=='y2025')].vQPEDom.sum() + data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEHYDRC')) & (data_results['vQPEDom'].sYear=='y2025')].vQPEDom.sum() + data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEMNHYDR')) & (data_results['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030hydro=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEHYDRR')) & (data_results['vQPEDom'].sYear=='y2030')].vQPEDom.sum() + data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEHYDRC')) & (data_results['vQPEDom'].sYear=='y2030')].vQPEDom.sum() + data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEMNHYDR')) & (data_results['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035hydro=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEHYDRR')) & (data_results['vQPEDom'].sYear=='y2035')].vQPEDom.sum() + data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEHYDRC')) & (data_results['vQPEDom'].sYear=='y2035')].vQPEDom.sum() + data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEMNHYDR')) & (data_results['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040hydro=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEHYDRR')) & (data_results['vQPEDom'].sYear=='y2040')].vQPEDom.sum() + data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEHYDRC')) & (data_results['vQPEDom'].sYear=='y2040')].vQPEDom.sum() + data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEMNHYDR')) & (data_results['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045hydro=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEHYDRR')) & (data_results['vQPEDom'].sYear=='y2045')].vQPEDom.sum() + data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEHYDRC')) & (data_results['vQPEDom'].sYear=='y2045')].vQPEDom.sum() + data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEMNHYDR')) & (data_results['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050hydro=data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEHYDRR')) & (data_results['vQPEDom'].sYear=='y2050')].vQPEDom.sum() + data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEHYDRC')) & (data_results['vQPEDom'].sYear=='y2050')].vQPEDom.sum() + data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith('sPEMNHYDR')) & (data_results['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020nuclear=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPENUCLE')) & (data_results['vQPEImp'].sYear=='y2020')].vQPEImp.sum()\n", + "y2025nuclear=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPENUCLE')) & (data_results['vQPEImp'].sYear=='y2025')].vQPEImp.sum()\n", + "y2030nuclear=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPENUCLE')) & (data_results['vQPEImp'].sYear=='y2030')].vQPEImp.sum()\n", + "y2035nuclear=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPENUCLE')) & (data_results['vQPEImp'].sYear=='y2035')].vQPEImp.sum()\n", + "y2040nuclear=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPENUCLE')) & (data_results['vQPEImp'].sYear=='y2040')].vQPEImp.sum()\n", + "y2045nuclear=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPENUCLE')) & (data_results['vQPEImp'].sYear=='y2045')].vQPEImp.sum()\n", + "y2050nuclear=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPENUCLE')) & (data_results['vQPEImp'].sYear=='y2050')].vQPEImp.sum()\n", + "\n", + "y2020impcoal=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPEIMPCO')) & (data_results['vQPEImp'].sYear=='y2020')].vQPEImp.sum()\n", + "y2025impcoal=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPEIMPCO')) & (data_results['vQPEImp'].sYear=='y2025')].vQPEImp.sum()\n", + "y2030impcoal=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPEIMPCO')) & (data_results['vQPEImp'].sYear=='y2030')].vQPEImp.sum()\n", + "y2035impcoal=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPEIMPCO')) & (data_results['vQPEImp'].sYear=='y2035')].vQPEImp.sum()\n", + "y2040impcoal=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPEIMPCO')) & (data_results['vQPEImp'].sYear=='y2040')].vQPEImp.sum()\n", + "y2045impcoal=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPEIMPCO')) & (data_results['vQPEImp'].sYear=='y2045')].vQPEImp.sum()\n", + "y2050impcoal=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPEIMPCO')) & (data_results['vQPEImp'].sYear=='y2050')].vQPEImp.sum()\n", + "\n", + "y2020nagas=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPENAGAS')) & (data_results['vQPEImp'].sYear=='y2020')].vQPEImp.sum()\n", + "y2025nagas=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPENAGAS')) & (data_results['vQPEImp'].sYear=='y2025')].vQPEImp.sum()\n", + "y2030nagas=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPENAGAS')) & (data_results['vQPEImp'].sYear=='y2030')].vQPEImp.sum()\n", + "y2035nagas=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPENAGAS')) & (data_results['vQPEImp'].sYear=='y2035')].vQPEImp.sum()\n", + "y2040nagas=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPENAGAS')) & (data_results['vQPEImp'].sYear=='y2040')].vQPEImp.sum()\n", + "y2045nagas=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPENAGAS')) & (data_results['vQPEImp'].sYear=='y2045')].vQPEImp.sum()\n", + "y2050nagas=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPENAGAS')) & (data_results['vQPEImp'].sYear=='y2050')].vQPEImp.sum()\n", + "\n", + "y2020lngas=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPELNGAS')) & (data_results['vQPEImp'].sYear=='y2020')].vQPEImp.sum()\n", + "y2025lngas=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPELNGAS')) & (data_results['vQPEImp'].sYear=='y2025')].vQPEImp.sum()\n", + "y2030lngas=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPELNGAS')) & (data_results['vQPEImp'].sYear=='y2030')].vQPEImp.sum()\n", + "y2035lngas=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPELNGAS')) & (data_results['vQPEImp'].sYear=='y2035')].vQPEImp.sum()\n", + "y2040lngas=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPELNGAS')) & (data_results['vQPEImp'].sYear=='y2040')].vQPEImp.sum()\n", + "y2045lngas=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPELNGAS')) & (data_results['vQPEImp'].sYear=='y2045')].vQPEImp.sum()\n", + "y2050lngas=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPELNGAS')) & (data_results['vQPEImp'].sYear=='y2050')].vQPEImp.sum()\n", + "\n", + "y2020croil=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPECROIL')) & (data_results['vQPEImp'].sYear=='y2020')].vQPEImp.sum()\n", + "y2025croil=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPECROIL')) & (data_results['vQPEImp'].sYear=='y2025')].vQPEImp.sum()\n", + "y2030croil=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPECROIL')) & (data_results['vQPEImp'].sYear=='y2030')].vQPEImp.sum()\n", + "y2035croil=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPECROIL')) & (data_results['vQPEImp'].sYear=='y2035')].vQPEImp.sum()\n", + "y2040croil=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPECROIL')) & (data_results['vQPEImp'].sYear=='y2040')].vQPEImp.sum()\n", + "y2045croil=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPECROIL')) & (data_results['vQPEImp'].sYear=='y2045')].vQPEImp.sum()\n", + "y2050croil=data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith('sPECROIL')) & (data_results['vQPEImp'].sYear=='y2050')].vQPEImp.sum()\n", + "\n", + "\n", + "\n", + "\n", + "#Visualize the results in a bar plot for each year unstacking the results for Solar PV and Hydro\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "solpv = [y2020solpv, y2025solpv, y2030solpv, y2035solpv, y2040solpv, y2045solpv, y2050solpv]\n", + "hydro = [y2020hydro, y2025hydro, y2030hydro, y2035hydro, y2040hydro, y2045hydro, y2050hydro]\n", + "wind = [y2020wind, y2025wind, y2030wind, y2035wind, y2040wind, y2045wind, y2050wind]\n", + "solte = [y2020solte, y2025solte, y2030solte, y2035solte, y2040solte, y2045solte, y2050solte]\n", + "solth = [y2020solth, y2025solth, y2030solth, y2035solth, y2040solth, y2045solth, y2050solth]\n", + "biomec = [y2020biomec, y2025biomec, y2030biomec, y2035biomec, y2040biomec, y2045biomec, y2050biomec]\n", + "biomaw = [y2020biomaw, y2025biomaw, y2030biomaw, y2035biomaw, y2040biomaw, y2045biomaw, y2050biomaw]\n", + "biomfw = [y2020biomfw, y2025biomfw, y2030biomfw, y2035biomfw, y2040biomfw, y2045biomfw, y2050biomfw]\n", + "swast = [y2020swast, y2025swast, y2030swast, y2035swast, y2040swast, y2045swast, y2050swast]\n", + "bioethpi = [y2020bioethpi, y2025bioethpi, y2030bioethpi, y2035bioethpi, y2040bioethpi, y2045bioethpi, y2050bioethpi]\n", + "biodiepi = [y2020biodiepi, y2025biodiepi, y2030biodiepi, y2035biodiepi, y2040biodiepi, y2045biodiepi, y2050biodiepi]\n", + "biogas = [y2020biogas, y2025biogas, y2030biogas, y2035biogas, y2040biogas, y2045biogas, y2050biogas]\n", + "nuclear = [y2020nuclear, y2025nuclear, y2030nuclear, y2035nuclear, y2040nuclear, y2045nuclear, y2050nuclear]\n", + "impcoal = [y2020impcoal, y2025impcoal, y2030impcoal, y2035impcoal, y2040impcoal, y2045impcoal, y2050impcoal]\n", + "nagas = [y2020nagas, y2025nagas, y2030nagas, y2035nagas, y2040nagas, y2045nagas, y2050nagas]\n", + "lngas = [y2020lngas, y2025lngas, y2030lngas, y2035lngas, y2040lngas, y2045lngas, y2050lngas]\n", + "croil = [y2020croil, y2025croil, y2030croil, y2035croil, y2040croil, y2045croil, y2050croil]\n", + "\n", + "\n", + "# Graph in a bar stack plot with different colors for each energy source\n", + "# fig, ax = plt.subplots()\n", + "# barWidth = 0.85\n", + "# plt.bar(years, solpv, color='gold', width=barWidth)\n", + "# plt.bar(years, hydro, bottom=solpv, color='blue', width=barWidth)\n", + "# plt.bar(years, wind, bottom=np.array(solpv)+np.array(hydro), color='cornflowerblue', width=barWidth)\n", + "# plt.bar(years, solte, bottom=np.array(solpv)+np.array(hydro)+np.array(wind), color='orange', width=barWidth)\n", + "# plt.bar(years, solth, bottom=np.array(solpv)+np.array(hydro)+np.array(wind)+np.array(solte), color='goldenrod', width=barWidth)\n", + "# plt.bar(years, biomec, bottom=np.array(solpv)+np.array(hydro)+np.array(wind)+np.array(solte)+np.array(solth), color='tan', width=barWidth)\n", + "# plt.bar(years, biomaw, bottom=np.array(solpv)+np.array(hydro)+np.array(wind)+np.array(solte)+np.array(solth)+np.array(biomec), color='darkorange', width=barWidth)\n", + "# plt.bar(years, biomfw, bottom=np.array(solpv)+np.array(hydro)+np.array(wind)+np.array(solte)+np.array(solth)+np.array(biomec)+np.array(biomaw), color='sandybrown', width=barWidth)\n", + "# plt.bar(years, swast, bottom=np.array(solpv)+np.array(hydro)+np.array(wind)+np.array(solte)+np.array(solth)+np.array(biomec)+np.array(biomaw)+np.array(biomfw), color='sienna', width=barWidth)\n", + "# plt.bar(years, bioethpi, bottom=np.array(solpv)+np.array(hydro)+np.array(wind)+np.array(solte)+np.array(solth)+np.array(biomec)+np.array(biomaw)+np.array(biomfw)+np.array(swast), color='maroon', width=barWidth)\n", + "# plt.bar(years, biodiepi, bottom=np.array(solpv)+np.array(hydro)+np.array(wind)+np.array(solte)+np.array(solth)+np.array(biomec)+np.array(biomaw)+np.array(biomfw)+np.array(swast)+np.array(bioethpi), color='brown', width=barWidth)\n", + "# plt.bar(years, biogas, bottom=np.array(solpv)+np.array(hydro)+np.array(wind)+np.array(solte)+np.array(solth)+np.array(biomec)+np.array(biomaw)+np.array(biomfw)+np.array(swast)+np.array(bioethpi)+np.array(biodiepi), color='lightcoral', width=barWidth)\n", + "# plt.bar(years, nuclear, bottom=np.array(solpv)+np.array(hydro)+np.array(wind)+np.array(solte)+np.array(solth)+np.array(biomec)+np.array(biomaw)+np.array(biomfw)+np.array(swast)+np.array(bioethpi)+np.array(biodiepi)+np.array(biogas), color='rosybrown', width=barWidth)\n", + "# plt.bar(years, impcoal, bottom=np.array(solpv)+np.array(hydro)+np.array(wind)+np.array(solte)+np.array(solth)+np.array(biomec)+np.array(biomaw)+np.array(biomfw)+np.array(swast)+np.array(bioethpi)+np.array(biodiepi)+np.array(biogas)+np.array(nuclear), color='black', width=barWidth)\n", + "# plt.bar(years, nagas, bottom=np.array(solpv)+np.array(hydro)+np.array(wind)+np.array(solte)+np.array(solth)+np.array(biomec)+np.array(biomaw)+np.array(biomfw)+np.array(swast)+np.array(bioethpi)+np.array(biodiepi)+np.array(biogas)+np.array(nuclear)+np.array(impcoal), color='dimgray', width=barWidth)\n", + "# plt.bar(years, lngas, bottom=np.array(solpv)+np.array(hydro)+np.array(wind)+np.array(solte)+np.array(solth)+np.array(biomec)+np.array(biomaw)+np.array(biomfw)+np.array(swast)+np.array(bioethpi)+np.array(biodiepi)+np.array(biogas)+np.array(nuclear)+np.array(impcoal)+np.array(nagas), color='silver', width=barWidth)\n", + "# plt.bar(years, croil, bottom=np.array(solpv)+np.array(hydro)+np.array(wind)+np.array(solte)+np.array(solth)+np.array(biomec)+np.array(biomaw)+np.array(biomfw)+np.array(swast)+np.array(bioethpi)+np.array(biodiepi)+np.array(biogas)+np.array(nuclear)+np.array(impcoal)+np.array(nagas)+np.array(lngas), color='whitesmoke', width=barWidth)\n", + "\n", + "# plt.plot([Total_GWh_Households_TEST_2020,Total_GWh_Households_TEST_2025,Total_GWh_Households_TEST_2030,Total_GWh_Households_TEST_2035,Total_GWh_Households_TEST_2040,Total_GWh_Households_TEST_2045,Total_GWh_Households_TEST_2050], color='black', label='Residential consumption', linewidth=2, linestyle='dashed',marker='o', markersize=5)\n", + "# plt.plot([Total_GWh_Industry_2020,Total_GWh_Industry_2025,Total_GWh_Industry_2030,Total_GWh_Industry_2035,Total_GWh_Industry_2040,Total_GWh_Industry_2045,Total_GWh_Industry_2050],color='cyan', label='Residential consumption', linewidth=2, linestyle='dashed',marker='o', markersize=5)\n", + "# plt.plot([Total_GWh_Transport_2020,Total_GWh_Transport_2025,Total_GWh_Transport_2030,Total_GWh_Transport_2035,Total_GWh_Transport_2040,Total_GWh_Transport_2045,Total_GWh_Transport_2050],color='green', label='Residential consumption', linewidth=2, linestyle='dashed',marker='o', markersize=5)\n", + "# plt.plot([Total_GWh_Services_2020,Total_GWh_Services_2025,Total_GWh_Services_2030,Total_GWh_Services_2035,Total_GWh_Services_2040,Total_GWh_Services_2045,Total_GWh_Services_2050],color='red', label='Services sector consumption', linewidth=2, linestyle='dashed',marker='o', markersize=5)\n", + "\n", + "plt.stackplot(years, solpv, hydro, wind, solte, solth, biomec, biomaw, biomfw, swast, bioethpi, biodiepi, biogas, nuclear, impcoal, nagas, lngas, croil, colors=['gold', 'blue', 'cornflowerblue', 'orange', 'goldenrod', 'tan', 'darkorange', 'sandybrown', 'sienna', 'maroon', 'brown', 'lightcoral', 'rosybrown', 'black', 'dimgray', 'silver', 'whitesmoke'])\n", + "# Add a legend outside of the plot\n", + "plt.title('Primary energy consumption by source')\n", + "plt.xlabel('Year')\n", + "plt.ylabel('[GWh]')\n", + "plt.legend(['Solar PV', 'Hydro', 'Wind', 'Solar Termoeléctrica', 'Solar Térmica', 'BiomasaEC', 'BiomassAW', 'BiomassFW', 'Residuos Sólidos', 'BioetanolPI', 'BiodieselPI', 'Biogás', 'Nuclear', 'Carbón Importado', 'NG', 'LNG', 'Crudo'], bbox_to_anchor=(1.05, 1), loc='upper left')\n", + "plt.show()\n", + "\n", + "\n", + "\n", + "\n", + "# plt.plot(years, solpv, label='Solar PV',color='yellow')\n", + "# plt.plot(years, hydro, label='Hydro',color='blue')\n", + "# plt.plot(years, wind, label='Wind',color='green')\n", + "# plt.plot(years,solte, label='Solar Termoeléctrica',color='orange')\n", + "# plt.plot(years,solth, label='Solar Térmica',color='red')\n", + "# plt.plot(years,biomec, label='BiomasaEC',color='purple')\n", + "# plt.plot(years,biomaw, label='BiomassAW',color='pink')\n", + "# plt.plot(years,biomfw, label='BiomassFW')\n", + "# plt.plot(years,swast, label='Residuos Sólidos')\n", + "# plt.plot(years,bioethpi, label='BioetanolPI')\n", + "# plt.plot(years,biodiepi, label='BiodieselPI')\n", + "# plt.plot(years,biogas, label='Biogás')\n", + "# plt.plot(years,nuclear, label='Nuclear')\n", + "# plt.plot(years,impcoal, label='Carbón Importado',color='black')\n", + "# plt.plot(years,nagas, label='NG')\n", + "# plt.plot(years,lngas, label='LPG')\n", + "# plt.plot(years,croil, label='Crudo')\n", + "# plt.xlabel('Year')\n", + "# plt.ylabel('[GWh]')\n", + "# plt.title('Primary energy')\n", + "# Add a legend outside of the plot\n", + "# Change the color of the plots to gradient of blue\n", + "\n", + "# plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')\n", + "# plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Total Consumption by Sector\n", + "years = ['y2020', 'y2025', 'y2030', 'y2035', 'y2040', 'y2045', 'y2050']\n", + "sectors = {\n", + " 'solpv': 'sPESOLPV',\n", + " 'wind': 'sPEWINON',\n", + " 'solth': 'sPESOLTH',\n", + " 'solte': 'sPESOLTE',\n", + " 'biomec': 'sPEBIOMEC',\n", + " 'biomaw': 'sPEBIOMAW',\n", + " 'biomfw': 'sPEBIOMFW',\n", + " 'swast': 'sPESWAST',\n", + " 'bioethpi': 'sPEBIOETHPI',\n", + " 'biodiepi': 'sPEBIODIEPI',\n", + " 'biogas': 'sPEBIOGAS',\n", + " 'hydro': ['sPEHYDRR', 'sPEHYDRC', 'sPEMNHYDR'],\n", + " 'nuclear': 'sPENUCLE',\n", + " 'impcoal': 'sPEIMPCO',\n", + " 'nagas': 'sPENAGAS',\n", + " 'lngas': 'sPELNGAS',\n", + " 'croil': 'sPECROIL'\n", + "}\n", + "\n", + "# Function to calculate sum for each sector and year\n", + "def calculate_sum(sector, year):\n", + " if isinstance(sector, list):\n", + " return sum(data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith(s)) & (data_results['vQPEDom'].sYear == year)].vQPEDom.sum() + data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith(s)) & (data_results['vQPEImp'].sYear == year)].vQPEImp.sum() for s in sector)\n", + " return data_results['vQPEDom'][(data_results['vQPEDom'].sPE.str.startswith(sector)) & (data_results['vQPEDom'].sYear == year)].vQPEDom.sum() + data_results['vQPEImp'][(data_results['vQPEImp'].sPE.str.startswith(sector)) & (data_results['vQPEImp'].sYear == year)].vQPEImp.sum()\n", + "\n", + "# Dictionary to store results\n", + "results = {sector: [calculate_sum(sectors[sector], year) for year in years] for sector in sectors}\n", + "\n", + "\n", + "# Visualize the results in a bar plot for each year unstacking the results for Solar PV and Hydro\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "# Extracting the results for plotting\n", + "solpv = results['solpv']\n", + "hydro = results['hydro']\n", + "wind = results['wind']\n", + "solte = results['solte']\n", + "solth = results['solth']\n", + "biomec = results['biomec']\n", + "biomaw = results['biomaw']\n", + "biomfw = results['biomfw']\n", + "swast = results['swast']\n", + "bioethpi = results['bioethpi']\n", + "biodiepi = results['biodiepi']\n", + "biogas = results['biogas']\n", + "nuclear = results['nuclear']\n", + "impcoal = results['impcoal']\n", + "nagas = results['nagas']\n", + "lngas = results['lngas']\n", + "croil = results['croil']\n", + "\n", + "# Graph in a bar stack plot with different colors for each energy source\n", + "plt.stackplot(years, solpv, hydro, wind, solte, solth, biomec, biomaw, biomfw, swast, bioethpi, biodiepi, biogas, nuclear, impcoal, nagas, lngas, croil, colors=['gold', 'blue', 'cornflowerblue', 'orange', 'goldenrod', 'tan', 'darkorange', 'sandybrown', 'sienna', 'maroon', 'brown', 'lightcoral', 'rosybrown', 'black', 'dimgray', 'silver', 'whitesmoke'])\n", + "# Add a legend outside of the plot\n", + "plt.title('Primary energy consumption by source')\n", + "plt.xlabel('Year')\n", + "plt.ylabel('[GWh]')\n", + "plt.legend(['Solar PV', 'Hydro', 'Wind', 'Solar Termoeléctrica', 'Solar Térmica', 'BiomasaEC', 'BiomassAW', 'BiomassFW', 'Residuos Sólidos', 'BioetanolPI', 'BiodieselPI', 'Biogás', 'Nuclear', 'Carbón Importado', 'NG', 'LNG', 'Crudo'], bbox_to_anchor=(1.05, 1), loc='upper left')\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Primary energy consumption by source" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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ms9t6NChJCcnM3PmTKZPn05iYiIPPPAAycnJNvtOnDiR8PBwPvvsM+666y4WLFjA999/b7399ddf58MPP+Tuu++29mm89dZbfPzxxzbHufprl5+fz0MPPcTu3bv53//+x4wZMzh06BCLFi2y3mfw4MHk5eXx22+/2Rxr9erV9O3bFxcXlyKf3zvvvMM777xDZGQkn332GYMHD+bdd99l3rx51q/P6NGj8ff35/333+fFF19kz549DBkyxOb5m81mnnvuOfr27cu8efNo1aoV77zzDv/88w8Au3btYtKkSfTq1Yv58+fz4osvsm3bNiZMmFBkXdezZ88evvrqK6ZMmcKMGTOIi4vjscceY8aMGTz++OO8//77nD59mokTJ9rcLyYmhtmzZ/P0008za9YsUlNTGTFiBOfOnaNZs2a8+uqrALz66qtFnhpUFIWxY8eyYMEC7rvvPuv38IMPPii0/7p169i4cSMvv/wy77//PhcuXOCZZ56xCdxFWbt2LVFRUbz99ttMnjyZTZs28eijj2IymejcuTPVqlUr8jVct25dwsPDizzmCy+8QFxcHFOnTmX+/Pk0bdqUyZMns23bNgCOHj3KwIEDOXnyJC+//DLvvvsuGo2Ghx56iB07dlz/m1GEr7/+mpCQED755BMGDx5MVlYWDzzwANu3b+eFF17go48+wsnJidGjR5OQkAAU/2fjRm70OizKsGHDCv2OOn78OEeOHKFRo0YAxMXF4ebmRtWqVW32q1OnDufOnSMrK4vAwEBef/11a6AqsHHjRhwcHKhbty65ubkkJSVRr149m318fHxwd3e3/i4VotxSRIkbMWKEMnz4cMVgMFg/Lly4oPz6669K27ZtlSFDhihms9m6b1hYmJKXl2e9f2JiohIUFKT8+OOPiqIoyo8//qgEBQUp33zzjXWfX375RQkKClI++OAD67YDBw4oQUFByoYNGxRFUZSVK1cqjzzyiGIymaz7mEwmJTw8XHnllVdsHut///ufzXP47rvvlODgYOXEiRPWbb169bLeryjjx49XIiIilIyMDOu21NRUJTw8XHn77bcVRVGUbdu2KUFBQcrs2bNt7hsZGak8/vjjiqIoyrFjx5Tg4GDl888/t9ln9uzZSkhIiJKSknLNr93333+vBAUFKQcOHLBuy8jIUNq1a6d0797dum3IkCHK8OHDrZ/v2rVLCQoKUnbv3l3kc0tPT1eaNm2qTJ8+3Wb7G2+8oYwZM0YxmUxKx44dldGjR9vcfvz4caVZs2bKzJkzFUW5/L1cvny5dZ+8vDwlJCREmTZtmqIoivL5558rLVu2tHlemzZtUubOnWt93QQFBSkffvihzWN9+OGHSlBQkPXzyZMnK0FBQcrRo0et21599VUlKChI2bp1q3XbwoULlaCgICU9Pd3mfv/99591n7NnzyohISHKrFmzFEW5/H3ctm2bdZ8RI0YoI0aMsNYbFBSkrFmzxqbGjz/+WAkKClJiY2Ot9wkLC7N5zaxcubLQ9/Bq3bt3VyIiIpSsrCzrtg0bNihBQUHKH3/8oSiKorz33ntKixYtlMzMTEVRFCUnJ0dp1aqV8tlnn13zuM2bN1c+/fRT6+cmk0l5++23lV27dimKoijPPvus0q5dO5t6DQaD0rt3b2XQoEHX/Npc/fUpeA533HGHzT5Lly5VgoODlejoaOu27OxspVevXsry5cuL/bNxtWv9Trne67A4cnJylCFDhigtWrRQTp48qSiKorzyyitK586dC+27fPlyJSgoSDlz5kyRx1q/fr0SHBysvPHGG4qiKMq5c+cK1Vigc+fOyssvv1zsOoVQg4xglZL//vuPZs2aWT8iIiIYP348zZs357333rNpcK9fv77NEPi1tGzZ0vp/X19fAMLCwqzbvL29AcsVXgD33HMP8+fPx2AwcOjQIdatW8eHH36IyWTCYDDYHLtJkyY2n/fr1w9nZ2frCMDu3btJSEjg3nvvvWZ927Zto23btjg7O2M0GjEajbi7u9O6dWu2bt16zecCUKNGDbKzs63HURSFyMhI63GMRiORkZHk5eXZnI65+mu3bds2AgMDradiwdIP1717d5vHGzRoEDt37iQpKQmAlStXUq9evUJ1Fdi7dy9Go7HQ6N3LL7/MggULiI+P5/z589x11102t9euXZuWLVsWGt248nEcHR3x8fGxPv82bdqQk5PDXXfdxXvvvcfOnTvp1KkTTz/99DUvjLgWLy8vGjRoYP3cz88PuP7rBqBWrVq0bt3a+nm1atVo2bIl//33X7Eed8eOHej1evr06WOz/e6777beXqBhw4a4u7tbP69evTrANU/VFujatavNqarIyEj0er21xkGDBpGdnc2GDRsA2LBhA9nZ2dxzzz3XPGa7du2YO3cu48aN4/vvv+fChQtMnjyZVq1aWevu3r27Tb16vZ5+/fpx8OBBsrKyrlvz1a7+udu1axe1atWy2e7i4sK6deu47777bupnoziu9zq8kczMTB5//HEOHDjArFmzCAgIAG48dYdWW/htZ/369YwfP57w8HBeeOEFAJtTyUW52Z8FIcqaNLmXkmbNmjF16lTA8ovAyckJf39/m1/MBdzc3Ip1zKLue63TWQC5ubm88cYbrF69GqPRSK1atWjZsiV6vb7QL8Er36gKHqtPnz789NNPPP3006xateq6AQQgLS2NX3/9lV9//bXQbT4+PjafOzs723yu1WqtNaWlpQGWkFeUK3uRrv7apaamWsPnla7e1rdvX9566y1Wr17NmDFjWLt2LY899tg1ntnlmq5+HlffXhBgruTn50d0dLTNtus9/5YtWzJv3jwWL17MF198wbx58/Dz82Ps2LE3PQ1CUa8ZKPz9vlpByLmSr69vocvxryU9PZ0qVaqg0+lsthecNrqy/+3q13DBG/CN3mCvPgWl1WqpUqWKNSjWqVOHtm3bsmrVKu655x5WrVpFREREkc+twOzZs/nss89Yu3Yt69atQ6vVEhERwbRp0wgICCA9Pf2a32NFUcjMzLxuzVe7+vuQlpZW5Ov3ytuheD8bxXG91+H1nD59mscff5z4+Hhmz57NHXfcYb3N3d29yKBZ8LXx8PCw2b548WJmzpxJ27Zt+fjjj3FycrIeB7jmsa4+jhDljQSsUuLm5kZISIiqNUyfPp1169bxwQcfEBERYf1lXnC1zo0MGjSIlStXsn//ftatW8eYMWOuu7+HhwcRERHWZvMr6fXFf6l5enoC8OWXXxYZPq935VD16tWtvSpXuroHzM3NjT59+rB27VqCgoLIzs5mwIABN6wpJSXFpm/k1KlTnDhxgipVqgBw4cKFQvc9f/689fbi6ty5M507dyYnJ4dt27axZMkS3nzzTcLCwggNDQUo1KNU3JGH4khNTS207cKFC9d987+Sl5cXqampmEwmm5B17tw5gJv+ehSlIGwUMJlMhQL2oEGD+N///kdcXBz//vsv77777nWP6eHhwQsvvMALL7zAsWPH2LhxI5988glTp05l3rx5eHl5XfN7XPC8jh8/DhQOiFlZWTf8Y8rDw4OTJ08W2r579268vLxu62ejpBw+fJgxY8aQl5fHokWLaNOmjc3t9evXJzMzk5SUFJs/SI4fP05AQIA11CmKwvTp01m6dCl33XUXM2bMsBmNdnNzo3r16tavZ4Hk5GSysrJsRmaFKI/kFKEd27VrF+3ateOOO+6whquDBw+SkpJyw9EBsJyqqlu3LrNmzSIjI+O6AQSgbdu2HD16lCZNmhASEkJISAjNmzdn8eLF1tM0xVFwaio1NdV6nJCQEFJSUpgzZ06hN9arazh58qTNVXG5ublFNu4OHjyY2NhYvvzyyxuObISGhuLg4MCff/5ps33RokWMHz+eRo0aUbVqVdasWWNze2JiInv37rWeYiqOmTNnMmjQIBRFwcXFhe7duzN58mTg8tWn7u7uhUYrdu/eXezHuJGEhATi4uKsn589e5Y9e/ZYw/nVI1NXa9u2LUajsdCFBAVXoF6ryfxmbNmyBaPRaP183bp1GI1G2rVrZ93Wu3dvXFxceP3113Fzc7MZablaUlISXbt2tdZcv359Hn30USIiIqxf9zZt2vDnn3/ajFSZTCZ++eUXQkJCcHR0tI68FFxsApYRvSu/ntfSunVrEhMTOXLkiHVbXl4ezzzzDD/88MNt/WyUhNOnTzNq1Cg0Gg3ffvttoXAFEBERAWDzvc/Pz2fTpk107NjRuu39999n6dKljBo1infffbfINomOHTuyadMmm4lF161bh06no3379iX51IQocTKCZcdCQ0NZu3Yt3377LQ0aNODQoUN8+umnaDSaG/a3FBg0aBDvvfceXbp0uW4AAXjyyScZOnQojz/+OA888ABOTk4sW7aM33//nQ8//LDYdQcHB3P33XfzyiuvkJSURPPmza2nImrVqkXdunWved+77rqLefPm8dRTT/Hss8/i6enJF198QXJycqG/7sPDw6lXrx47duxg9uzZ163Jx8eHBx98kMWLF+Po6Ejbtm3Zt28f3377LZMmTUKr1TJ+/HhefPFFJkyYwN13301qaiofffQRXl5eRY7qXUv79u354osvmDJlCnfffTcGg4EFCxbg7e1tfVPp1q0bv/zyC2FhYdSpU4cVK1YU+kv/diiXrgJ8/vnn0el01udRcIqy4PTMpk2b8PLyonHjxjb379KlC+3atePll1/m7NmzNG7cmB07djB//nzuvffeEpkz6/z58zzzzDOMHDmShIQE3n//fTp27GgzQuvi4kK/fv1YtmwZDzzwwHV7HQMCAqhRowZvvvkmmZmZ1K5dm4MHD/LXX3/x+OOPA/D000/z999/8+CDD/LYY4/h4ODAV199RWJiIgsWLAAsr19/f38+/vhj3N3d0Wg0fP7559c9nV9g4MCBLF26lCeeeIJx48ZRpUoVlixZgsFgYNiwYQQGBt7yz0ZJePPNN0lOTmbq1KlkZmayd+9e623u7u40bNiQgIAA7r33XmbMmEFeXh5169bliy++4OLFi9YrEGNiYpg/fz4hISH06dOn0CzvBX15jzzyCL/88guPPPIIo0aNsn6f77//fpkDS5R7ErDs2JQpUzAYDHzwwQfk5+dTq1YtnnjiCY4ePcoff/xxw8vgwdJI/N577zFw4MAb7tu4cWO+/vprZs+ezaRJk1AUhaCgID7++GN69OhxU7XPmDGDzz//nO+++44zZ87g6+tL3759ee655647eqLX61m4cCHTp0/n9ddfR6/Xc/fdd+Pt7V3kZd3dunUjJSXluiMbBV544QV8fX357rvvWLBgAbVq1eKVV15h6NChgOXN0c3Njc8//5ynnnoKd3d3OnfuzPjx4wv1C11P165deffdd1m0aJG1sT08PJwlS5ZYG9JffPFFjEYjM2fORK/X07dvXyZMmMDLL79c7Me5npo1azJ69GjeeustcnJyiIiI4NNPP7U+fqNGjbjrrrv4+uuv+eeffwqN3BWEig8//JDFixeTkpJCrVq1GD9+/E2FzesZNmwYGRkZPPXUUzg6OtK/f39eeOGFQs3P3bp1Y9myZcV6DX/00Ue8//77zJkzh9TUVPz9/Xn66aet/XmNGjXim2++sU7DodFoCA0NZcmSJdbRJZ1Ox4cffshbb73F+PHj8fPz46GHHuLYsWM3nFrA3d2dr776infeeYc33ngDs9lMixYtWLJkiXVql1v92bhdBaNQUPSs/W3btrXOxzVt2jQ8PT2ZP38+2dnZNGvWjC+++MI6i/v69etRFIUDBw4wZMiQQsdasmQJ7dq1o0GDBixatIh33nnHGjgffvhhxo0bV2rPU4iSolGK09EoKq2CZutNmzYV60pHtR05coRjx47Rq1cvmzfawYMHU6NGDT766CPrNkVR6NevH506deJ///ufGuWWS1OmTGHHjh388ccfapdSIl577TX27dtXaMJQIYQoTTKCJYq0cuVKYmNj+eabb3jyyScr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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Now make a pie chart for the year 2020 with the primary energy consumption by source\n", + "# Consider 6 sources: Renewables = Solar PV + Hydro + Wind + Solar Termoeléctrica + Solar Térmica + BiomasaEC + BiomassAW + BiomassFW + BioetanolPI + BiodieselPI + Biogás\n", + "# Nuclear = Nuclear\n", + "# Fossil = Crudo\n", + "# Coal = Carbón Importado\n", + "# Gas = NG + LNG\n", + "# Non-renewable waste = Residuos Sólidos\n", + "\n", + "# Calculate the total primary energy consumption for 2020\n", + "total_2020 = y2020solpv + y2020hydro + y2020wind + y2020solte + y2020solth + y2020biomec + y2020biomaw + y2020biomfw + y2020swast + y2020bioethpi + y2020biodiepi + y2020biogas + y2020nuclear + y2020impcoal + y2020nagas + y2020lngas + y2020croil\n", + "\n", + "# Calculate the percentage of each source\n", + "renewables = (y2020solpv + y2020hydro + y2020wind + y2020solte + y2020solth + y2020biomec + y2020biomaw + y2020biomfw + y2020bioethpi + y2020biodiepi + y2020biogas) / total_2020\n", + "nuclear = y2020nuclear / total_2020\n", + "fossil = y2020croil / total_2020\n", + "coal = y2020impcoal / total_2020\n", + "gas = (y2020nagas + y2020lngas) / total_2020\n", + "non_renewable_waste = y2020swast / total_2020\n", + "\n", + "# Create a pie chart\n", + "labels = ['Renewables', 'Nuclear', 'Oil product', 'Coal', 'Gas', 'Non-renewable waste']\n", + "sizes = [renewables, nuclear, fossil, coal, gas, non_renewable_waste]\n", + "colors = ['gold', 'green', 'darkorange', 'blue', 'grey', 'lightblue']\n", + "plt.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%')\n", + "plt.axis('equal')\n", + "plt.title('Primary energy consumption by source in 2020')\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Energy imported for all years" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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34gncpQpc5LVBqGc+lSoI2o1VBia5JGoSJLU6lCWhPmR/X6Czc0AFP38PCSTCffWLbRsWJ/wscQLfUEdp/ohjWT3InKuXsXee+7GE4qCHioEW1InZc6YlQ2SBLJM0NGk/1xvRdDPexBBq6lCpClzeg2REEQCgaCPELEgOv3003nvvff49NNPO93n008/5aOPPuLss8+OyeD6G5LBgDUUJfInsI4oGKWpgiRJmLKygPaFyMkglSy3NZJpTa6l/kgmE5ZBg8lecDQAtW+9cchEibQFdaQivqcYkhghal6+jAMPP4R78yaaFn2R8PPHC0WWW9N0U0AQSQaD3sw5EJYFoYiUOR2vljIXaYRIqyGSRQ2RQCDoG0QsiI4//niOPvporrjiCq655ho+/fRTtm/fzvbt2/nyyy+54YYbuPLKKzn11FOZO3duPMd8SGML1WP5axNXR6RFiIxRLC7NRcUA+Kuq4jKmSAk0NRJsagJJwjpwUFLHEo4hic1rteiiKScXSZLIO+EkJIsF766duNasTvh44oEcasoa7whDslLmmr9fSsXjj0Aohcuzc0dCzx9Pwg0q4h3hixStjig8Mq+5zAlThegjRCJlTiAQ9DWiutPfd999PPLIIzz99NP873//03+uKApWq5WLL76Y3/3udzEfZH/CVhISGgk0VtD7EEVYQwRgKSnBvXkTvsqKeA0rIrx7VbttS3EJhhRqBmxMotOcLohCtRGmrCxyjj6Whv+9T907b5FePjklzCd6Q2uEKEEpcwkURI6lS9T+UYpC+pSpuFavwrt/H7LXm1LXeE/RficMdnvK2FmbcnPx7trZJuItIkSteKNozApCEAkEgr5HxILoP//5D0cffTSXX345F110Ed988w179+5FURQGDBjA3LlzychoWyBbX1/P559/zllnnRXzgR+qWItDgiiBEaJglC5zAJZi1XHQV1UZlzFFiu4wlwINWcPRUuYSuZDW0BZ1miACyPvRCTR98RnevXto2biB9AkTEz6uWKJFGaKJavYETXAlKkLkWPItlU89AYpC1hHzKP7Fr9hx3TUEmxrx7tmDffTohIwjnqSSw5xGR9bbeoRICKJWUwVRQyQQCA5RIhZEN998M2VlZeTm5mKz2Tj66KO7fc3evXu5+eabhSCKguREiKIzVQAwl6j9fnyVSRZEKVg/BGGpVklOmdPH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BAKBQCAQCAQCQb8lpQRRIBDgrLPOYt26dRHtv3LlSs4//3ymT5/OvHnzuPHGG2lsbNS3y7LMgw8+yLx585gyZQoXX3wxe/fubXOMzz//nDPPPJOpU6eycOFC/vrXv+LxePTtXq+X2267jTlz5jB16lSuvfZa6uvro3pfCxcuZMyYMR3+eeGFF6I6FsC+ffsYM2YMS5cu1X/23XffccYZZzB58mSOP/543n///U5ff8stt/DHP/6xzc+6m/uDz9nZ3GvjKC8v57DDDmPmzJlt5j58PidNmsSsWbOYMmWKPvdPPvkkd9xxB3Doz32k17t2zhdeeKHL6/31119nzpw5jBkzhrFjx3L88ceze/dufXtDQwPnnXce48aNY8yYMUybNo0777xTv97vuusunnzyybjMeXl5OcceeywPPPAAsixHdbyDeeihh1i4cKH+/0h+zzUaGho44ogj+Pbbb6O61/zpT39i0qRJEd9rfvSjH3HOOee0Ocbnn3/Oqaeeyvjx4xk7dizl5eVcddVV+vx6vV6OPvpopk+f3uO5VxSF559/nlNPPZXy8nKmT5/Oueeey4cffhjVcTqit/M+d+5cTjjhhKju7wsWLGDs2LER39//9re/cf755+v7aPf38vJyJk6cyIQJE1iwYIF+n/d6vdx8882MGzeOKVOmRD3np59+OldddVW7nx9xxBGMGTOG/fv3t/n5I488wowZMwgEAhGfQyMe9/2enLMjuhuHy+Xitttu44gjjmDGjBlcfPHFbN++Xd/+3HPP6fd9gUAgSAYpJYieeuopRo0axcSJE7vdd+fOnfz6179mzJgxvPbaa9x///2sXbuW3/3ud/o+Dz/8MC+99BK33347r7zyCrIsc9FFF+Hz+QBYvnw5l19+OcceeyxvvfUWf/7zn/nggw+47bbb9GPceuutLF68mIceeojnnnuOHTt2cOWVV0b93i688EIWL17c7s+ZZ54Z9bEOZvv27VxyySXMmzePN998k7PPPpvrr7+e7777rs1+sixz33338eqrr7Y7Rizm/je/+Y0+jrPOOguv14vT6eSGG27Q5/6WW25h8eLFXHbZZQQCASwWC6NGjdLnftu2bXz99dcsX778kJ/7aOYc4G9/+1un1/u7777LLbfcgsfj4Y477uDaa69lz549nHPOOfr1/qtf/Yply5bx05/+lLvvvhubzcbrr7+uX++XX345Dz30EIsWLYr5nL/11luceuqpPPLIIzz11FNRH68ruvs916iqquLXv/41NTU1fPDBB1Fd7++++y5mszmie83555/Prl272LRpU7t7TU1NDWVlZdx4441kZGSwePFi/vCHPwDqvUaWZcxmM//85z97NPcPPvggjz/+OJdccgnvv/8+r7zyCocddhhXXXUVb7/9dlTH6o5o5722tpYBAwZEdY8pKCigsLAwovv7vn37eOqpp3TBrc35+PHj8fv9nHTSSeTk5DBs2DD9Pn/rrbeyZMkSLrroIkaPHh31nM+ePZtVq1a1+dnGjRtpbGyksLCQr7/+us225cuXc9hhh2EymSI+R2fE4r4fCyIZx+23387SpUt58MEHefXVVzEajVx00UV4vV4Azj33XP2+LxAIBElBSREcDocybdo0ZcuWLRHtf9999ynHHXecIsuy/rNly5YpZWVlyp49exSv16tMnTpVefHFF/XtTU1NSnl5ufLee+8piqIo1157rXLBBRe0Oe5bb72lTJgwQfF6vUplZaUyduxYZdGiRfr2HTt2KGVlZcrKlSsjfm8LFixQHnzwwYj37469e/cqZWVlypIlSxRFUZSbb75ZOeuss9rsc8011ygXXnih/v9t27YpP/nJT5TZs2cr8+fPV/7whz/o2yKZ+/BzdjX3P/7xj9vMvTaOpqYmZdKkScqYMWOURYsW6XMfPp/a3D/zzDPKWWeddUjPfTTXu3bOI488stPr/ZxzzlHGjx/f5nr/+9//rpSVlSnvvfeesnLlSqWsrEw555xz9O1ff/21UlZWpowfP16/3seMGaP84he/0PeJ9Zyff/75ymmnnRbxsTriwQcfVBYsWKAoihLR77miKMrrr7+uzJo1Szn99NOVsrIyZfLkyVHda2bNmqXMnz9f/1lH95pHH31UueSSS5QpU6Yoxx57rDJ27Ng295oTTzxRmTJlilJTU6MoinqvGTdunLJw4UJl+/bt+vV+xRVXKA888ECP5n7WrFnKM8880+7nV111VVLn/ZRTTlHKysqU//znPxGdS7vH/OMf/9DP2dn9vbKyUrnkkkuUyZMnK2PGjFFOOOEERVFa7+/h93ntHvP6668r48eP1+c8EAgohx9+uPLmm29GNedffvmlUlZWpuzfv1//2WOPPab85Cc/Uf74xz8qv/3tb/WfBwIBZerUqcoLL7wQ0bEPJtb3/Z6csyMiGcf06dOV559/Xv//xo0blbKyMmXdunX6z/79738rP//5z6Man0AgEMSKlIkQvfrqq5SUlDB69GhATd855phj2uzT3NxMeXk5ixYt4pRTTuGvf/0rkiTp27V/NzU1sWnTJlwuF3PmzNG3Z2VlMX78eJYtWwaoT7G1p7MaBoMBv9+P0+lkxYoVgPoUUGP48OEUFxfrx0gEW7Zs4Re/+AVTpkzh2GOPbfcEcPny5W3eJ6hjXrFiBYqiALBkyRJGjhzJf//7XwYNGtRm30jm3ul0AvDWW2/x+eefs3fvXo455hjeeOMNoHXuJ0yY0GbutXFkZmYyYMAAFEVh9uzZ+tyHz6c290cccQQ//PCDvq/GoTT30VzvS5YsAWDBggWcc845TJw4kaOPPpqvvvoKUK/3M844g0Ag0GYsdrsdg8HAsmXLWL58OTk5OW2in7NmzUKSJAKBgH69S5LE8uXLqaqqAmI/51arNeqn46+++irHHnss5eXlXHrppTQ1NenbIvk9B/jkk0+4+uqr+cc//gFAXl5eVPeaY445BkmSePzxxznyyCO54IIL9PNrY8jKysJsNvPuu+8ybdo00tLS2txrSktLmT17NgUFBYB6rwkGg7z++uts2rQJUK+dE088kZdeeokBAwZEPfcGg4ElS5a0SfsFuOmmm3jooYciPg7Edt7nzZsHoF//0d7fH3/8cS6//HIAfve73/H555/r51+/fj1ms5n33nuP3Nxcmpubgdb7e/h9XrvH+P1+PW1t9uzZGI1GfvSjH/G///0vqjmfMWMGZrOZlStX6j/7+uuvmTt3LnPnzmXJkiX6eTZs2IDL5eKII46I6Njxvu9Hw5o1azj77LP1e4923490HPn5+XzwwQfU1dXh8/n4z3/+Q05ODkOGDNFfc/zxx7Nq1SrWrl3b43EKBAJBT0kZQfTpp59y1FFH6f8/44wz2Lt3b5sQ+gcffEBWVhbz5s1j5MiRTJkypc0xnnjiCQoLCxkzZgyVlZUAlJaWttmnqKhI36bl8mv4/X6effZZJk6cSF5eHlVVVeTm5mK1Wjs9Rrxpbm7mggsuIDMzk9dff51bb72VRx55pM0+lZWVlJSUtBuj2+2moaEBUFMS7rzzTvLz89udI5K5X7RoEQBfffUVV199NR9++CHz5s3jpptuYvfu3TzxxBNIksT48ePbzH34OKxWK2azGavV2mbui4qKOHDggD73o0aNorS0FJvNdsjOfTTX+8yZMwF1cfl///d/fPDBB8ybN4/HHnuMvLw8xowZQ25uLtB6vTc3N/Pyyy9TWFhIZWUlVVVVDBkypM31LkkSBoOBkpKSNtd7bm6uLra099PbOff5fLz99tt88803nHrqqRG/7r///S9/+ctfuOCCC3jnnXeYNm0aL774or49kt9zgMcee4yf/vSn+gJ78uTJ+rZI7jUlJSXs37+flStX8vjjj1NeXo7RaOTpp5/Wz3P66afz0EMPMXjwYAAsFkube01dXR2DBg3iX//6F8cccwx/+tOfyM3NxWQytbnXHHXUUTgcDlasWBH13F9yySV88cUXzJ07lyuuuILnnnuOzZs3k5+fH9WCONbz/u2337bZL5r7uzbvo0aNIjc3F5fLxYMPPqiff+HChfq82+12PQ1Lu8dof2v39wkTJvD6669TUlLS5v4+f/58vv32WwoKCiKe87S0NKZMmaKnzblcLlatWsXcuXM5/PDD9f8DrFixgoEDBzJ06NBuj5uI+340PPfcc23uPdp9P9Jx3HnnnVRVVXH44YczZcoU3n77bZ544gkyMzP11xQUFDBx4kQ+++yzXo1VIBAIekJKCCJZlvnhhx8oKyvTfzZ27FgmTJjAu+++q//srbfe4pRTTsFoNLY7xl//+lcWLVrErbfeitlsxu12A+qiJByr1ap/YYYTCAS4/vrr2bp1K3/+858BcLvd7V7f1TG64rHHHmPq1Klt/txyyy3dvu7999/H7XZz9913M3r0aObOncuf/vSnNvt4PJ5249T+f3A+/8FEOvcff/wxoNaZLFy4kCFDhnD11VcjyzJ33XUXixYtQpIk7HZ7m7k/eBzhEb3wsX799ddt5j43N5dgMNhu30Nh7hVF6dH1ftlll+lzbzCov7qnnXZau+vd5XLx29/+Fq/XS3l5OV6vt921rF3vwWBQF2baPqNGjWpTFxGLOS8vL+exxx7jxhtv5Nxzz434OP/+97858cQTOffccxk+fDi/+c1vWLBggb492t9zrb5EEy0Q+b3GbDZz77338s4777By5UpOO+00NmzY0OkYJElqMwan08nbb7/Nxo0bGTx4MIqikJaWxm9/+9s2n4/dbmfQoEGsWrUq6rm/4IILeOKJ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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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4uWXX8aKFSvw6quvQpIkXH755fB4PACADRs24Nprr8WiRYvw1ltv4e6778YHH3yAe++9Vx1jz549GDx4ML799tuQf1OmTInovf3iF7/oNMa3336LZcuWRTROVxw4cABXXXUV5s+fjzfffBPnnXcebr75ZqxevTpkO0mS8NBDD+G1117rNEYs1v7KK69U53HuuefC7XbDbrfjD3/4g7r2d911F7799ltcc8018Pl8MBgMGDlypLr2+/fvx6pVq7Bhw4Z+v/aRrDkA/N///V+3x/u7776Lu+66Cy6XC/fddx9uvPFGHDlyBOeff756vF922WVYv349LrjgAvzpT3+CyWTC66+/rh7v1157Ld566y2Ul5fHfM3feustnHXWWXjsscfwzDPPRDRWb/T2PVeor6/HL3/5SzQ2NuKDDz6I6Hh/9913odfrwzrXXHLJJTh8+DB2797d6VzT2NiIiooK3H777cjMzMS3336LW265BYB8rikvL0dhYSE++OCDqNb+4YcfxpNPPomrrroK77//Pl599VXMmjULv/3tb/H222+HPU44RLruTU1NKC8vj+gcU1hYiKKiorDO78eOHcMzzzyjCm5lzceNGwev14vTTz8dubm5GDp0qHqeV84xt912G2bMmBHxms+ePRubN28OeWzXrl1oa2tDUVERVq1aFfLchg0bMGvWLOh0urDG74lYnPdjQTjzWLFiBdauXYuHH34Yr732GgRBwOWXXw632w0AuPjii9XzPkEQRFJgGsFqtbKpU6eyvXv3hrX9Qw89xBYvXswkSVIfW79+PauoqGBHjhxhbrebTZkyhb300kvq8+3t7ayyspK99957jDHGbrzxRnbppZeGjPvWW2+x8ePHM7fbzRhj7O6772ZXX311n97bySefzB5++OE+jRHM0aNHWUVFBVuzZg1jjLE777yTnXvuuSHb/O53v2O/+MUv1N/379/PfvrTn7LZs2ezBQsWsFtuuUV9Lpy1D95nT2v/k5/8JGTtlXm0t7eziRMnstGjR7OvvvpKXfuDBw+yiooKtmnTJnXtn3vuOXbRRRf167WP5HhX9nniiSd2e7yff/75bNy4cSHH+1//+ldWUVHB3nvvPbZp0yZWUVHBzj//fPX5VatWsYqKCjZu3Dj1eD/zzDPZiSeeGN3i+OlpzS+55BJ29tln92n8hx9+mJ188smMMRbW95wxxl5//XU2c+ZMtnTpUlZRUcEmTZoU0blm5syZbMGCBepjXZ1rHn/8cXbVVVexyZMns0WLFrExY8aEnGtOO+00NnnyZNbY2MgYk881Y8eOZQsXLmQ2m0093q+77jr297//Paq1mTlzJnvuuec6Pf7b3/42qet+5plnsoqKCvbGG2+EtS/lHPOPf/xD3Wd35/e6ujp21VVXsUmTJrHRo0ezU089lTEWOL8Hn+eVc8zrr7/Oxo8fz+6880529dVXM5/Px0444QT2/fffR7QmX3/9NauoqGDV1dXqY0888QT76U9/ym699Vb261//Wn3c5/OxKVOmsBdffDGifSjE+rwfzT67Ipx5TJs2jf3nP/9Rf9+1axerqKhg27dvVx974YUX2EUXXRTR/AiCIGKFZiJEr732GkpLSzFq1CgAcvrOKaecErKNzWZDZWUlvvrqK5x55pn485//DI7j1OeVn9vb27F79244HA7MmTNHfT47Oxvjxo3D+vXrAch3sZW7swo8z8Pr9cJutwOQ79qOGDEi9m84Avbu3Yuf/exnmDx5MhYtWtTpDuCGDRtC3icg37ncuHEjGGMAgDVr1mDEiBH43//+h4EDB4ZsG87aK+vx1ltv4YsvvsDRo0dxyimnYOXKlQACaz9+/PiQtVfmkZWVhfLycjDGMHv2bHXthw0bhpKSEqxfv15d+3nz5mHz5s3YtGlTv137SI73NWvWAABOPvlknH/++ZgwYQJ+9KMf4ZtvvgEgH+/nnHMOfD5fyFzMZjN4nsf69euxYcMG5ObmhkQ/Z86cCY7j4PP51M8XABoaGlBfX9+ndesOo9EY8d3x1157DYsWLUJlZSWuvvpqtLe3q8+F8z0HgE8//RQ33HAD/vGPfwAA8vPzIzrXnHLKKeA4Dk8++SROPPFEXHrpper+lTlkZ2dDr9fj3XffxdSpU2GxWELONWVlZZg9ezYKCwsByOcaURTx+uuvIzMzUz3XnHbaaXj55ZfVu+eRwPM81qxZE5L2CwB33HEH/vnPf0Y0VizXff78+QCgHv+Rnt+ffPJJXHvttQCA3/zmN/jiiy/U/e/YsQN6vR7vvfce8vLyYLPZAATO78HneeUco/zbtWsXRowYAUEQ8OMf/xjPPfdcRGs0ffp06PV6bNq0SX1s1apVmDt3LubOnYs1a9ao6XE7d+6Ew+HAvHnzwho73uf9SNiyZQvOO+889dyjnPfDnUdBQQE++OADNDc3w+Px4I033kBubi4GDx6svmbJkiXYvHkztm7dGvU8CYIgokUzguizzz7DSSedpP5+zjnn4OjRoyEh9A8++ADZ2dmYP38+RowYgcmTJ4eM8dRTT6GoqAijR49GXV0dAKCsrCxkm+LiYvU5JZdfwev14vnnn8eECROQn58PANi3bx8OHjyIc845B3PnzsVll12W0BO2zWbDpZdeiqysLLz++uu455578Nhjj4VsU1dXh9LS0pDHiouL4XQ60draCkBOSbj//vtRUFDQaR/hrP1XX30FAPjmm29www034KOPPsL8+fNxxx13oKqqCk899RQ4jsO4ceNC1j54HkajEXq9HkajMWTti4uLUVNTo669ksp06NChfrv2kRzvM2bMACBfXP7qV7/CBx98gPnz5+OJJ55Afn4+Ro8ejby8PACB491ms+GVV15BUVER6urqUF9fj8GDB4cc7xzHged5lJaWqsd7dXU1dDodLrjggpiuucfjwdtvv43vvvsOZ511Vtiv+9///oc//vGPuPTSS/HOO+9g6tSpeOmll9Tnw/meA8ATTzyBCy64QL3AnjRpkvpcOOea0tJSVFdXY9OmTXjyySdRWVkJQRDw7LPPqvtZunQp/vnPf2LQoEEAAIPBEHKuaW5uxsCBA/HII4/glFNOwW233Ya8vDxVICrnmieeeAJtbW244IILIl77q666Cl9++SXmzp2L6667Dv/+97+xZ88eFBQURHRBHOt1//7770O2i+T8rqz7yJEjkZeXB4fDgYcffljd/8KFC9V1N5vNqpBUzjHK/8r5ffz48Xj99dc7nWPee+89fPPNN1i3bl3Y62SxWDB58mQ1bc7hcGDz5s2YO3cuTjjhBPV3QK4RGzBgAIYMGdLruIk470fCv//975Bzj3LeD3ce999/P+rr63HCCSdg8uTJePvtt/HUU08hKytLfU1hYSEmTJiAzz//vE9zJQiCiAZNCCJJkrBt2zZUVFSoj40ZMwbjx4/Hu+++qz721ltv4cwzz4QgCJ3G+POf/4yvvvoK99xzD/R6PZxOJwD5oiQYo9HY5Z1Xn8+Hm2++Gfv27cPdd98NAKitrYXNZkNHRwfuuOMOPProoygsLMTy5cuxf//+iN7jE088gSlTpoT8u+uuu3p93fvvvw+n04k//elPGDVqFObOnYvbbrstZBuXy9XpfSq/H5/Pfzzhrv0nn3wCQK4zWbhwIQYPHowbbrgBkiThgQcewFdffQWO42A2m0PW/vh5BEf0gue6atWqkLUfMGAAPB5Pv1x7xlhUx/s111yjrj3Py1/ds88+u9Px7nA48Otf/xputxuVlZVwu91wOp0h81SOd1EUVWGmHO9msxkVFRUxXfPKyko88cQTuP3223HxxReHPc4LL7yA0047DRdffDGGDRuGK6+8EieffLL6fKTfc6W+RBEtQPjnGr1ejwcffBDvvPMONm3ahLPPPhs7d+7sdg4cx4XMwW634+2338auXbswaNAgMMZgsVjw61//GjU1Neq55s4770RJSQlEUYx47S+99FI89dRTmDlzJr799ls88MADOPPMM3HuuedGNE4s112SJOzevTvksUjO73q9HgMGDMCGDRtw33334cILL8SRI0e63D/P82pUIpjg83tOTg727duHa665JuT8/uc//xmMMfziF7+IaK1mz56tRojWrFkDs9mMSZMmIT8/H+PGjcO3334LAFi/fn3Y0aF4n/cjJfjco5z3d+zYEfY89uzZg0GDBuG5557Dyy+/jFmzZuHaa69FbW1tyOtGjRqFH374IaZzJwiCCAdNCKK2tjb4fL5Od7GWLVuGDz/8EB6PB1VVVdi8eXOnQniv14s//OEPeP7557FixQo1DcNkMgHo/IfB7XbDbDaHPGa323H11Vfj888/x7/+9S9UVlYCkO8+rl+/Hk899RSmTp2KSZMm4c9//jMGDRqEF154IaL3eMEFF+Dtt98O+RdcINwde/fuxdChQ0PupB1f8Gs0Gju9T+X349/r8YS79sofv2HDhqnbWCwWAMDXX3+NFStWwGQywePxhKx98DwYY50uVux2O/bs2YPa2tqQtR84cCCGDRvWL9fe4/FEdbwPGzZMPd5feeUVAFBFlbLmNTU1uOSSS7Bnzx48/fTTEAQBZrNZ/WyA0OM9MzMTw4cPBxA43k844QQwxmKy5itXrsTvf/97WCwWLFmyBBdffHGXorg79u7di4kTJ4Y8FvwZRPI9BwCr1QoAIZ8pEN65Jj8/H/fff796rpk+fTpcLle3c2CMhcxBp9PBZDLB6XRi48aNePTRR/H3v/8d69evR1NTU8i5pqysDFOnTo1q7U888UQ89thjWLdu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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA0QAAAHJCAYAAAClqPkBAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOydd3gU1feH323pPZBQQgel9xK69KoiKCq9SAvKDxQQvqCANAWkIyhIE0RRKUqLiNgFBAQLIL339J4t8/tjdyfZ7CbZJJvsBu77PDxkZ+7cuTOz5Z57zvkchSRJEgKBQCAQCAQCgUDwGKJ09gAEAoFAIBAIBAKBwFkIg0ggEAgEAoFAIBA8tgiDSCAQCAQCgUAgEDy2CINIIBAIBAKBQCAQPLYIg0ggEAgEAoFAIBA8tgiDSCAQCAQCgUAgEDy2CINIIBAIBAKBQCAQPLYIg0ggEAgEAoFAIBA8tgiDSCAQPFaIWtQCgUAgEAgyIwwiQaEzcOBAnnzySYt/tWvX5qmnnmLWrFnExcXlePzNmzd58skn2bFjRxGN2DEcPXrU6rqz/vvpp5+cPcwCM2XKFNq3b+/sYeRKfHw8kydP5vjx4w7p78knn2TFihW5trt58ybt2rUjOjo6T/3fuHGDuXPn0rlzZ+rWrUurVq0YPXo0v/zyi1XbFStWWL23atasSbNmzRg7diwXLlyQ2+b1fWnvdTqCZcuWMXPmTLvaLly4kKZNm1K/fn127dpVqOOyRXp6OmvWrKFr167Ur1+fLl26sHLlStLT0y3a/f333wwcOJAGDRrQqlUrFi9ebNXmzz//tGgzZ84cEhMTLdokJSUxa9YsWrZsSYMGDRgxYgSXL18u9OsUCASCxwG1swcgeDyoWbMmM2bMkF9rtVr+/fdfFi9ezNmzZ9m2bRsKhcLmsSEhIXz++eeUL1++qIbrUN5++21q1aplc1+VKlWKeDSPL2fPnmX37t306dOnyM4pSRJTp05l8ODBBAUF2X3cL7/8wvjx4wkJCWHYsGFUrlyZ6Oho9uzZw/Dhwxk8eDD/+9//rI77/PPP5b/1ej23b99myZIl9O/fn71791KyZEl5vyu+L0eOHEmXLl3o0qULzZs3z7bd+fPnWbduHX379uXZZ5+lcuXKRThKI3PmzOHrr78mIiKCOnXq8Pfff7Nq1Spu377NvHnzAKNRO3ToUOrXr8/SpUu5dOkSS5YsITY2lnfeeQeAc+fOMWTIEJo3b86KFSu4f/8+77//PleuXOHjjz+Wz/fGG29w+vRpJk2ahI+PDytXrmTQoEHs3bsXf3//Ir9+gUAgeJQQBpGgSPDx8aF+/foW25o0aUJSUhLLly/n9OnTVvvNuLm5ZbuvOFC1atViPX5B/jl48CDnz5+3mNjmxr1793j99depW7cuq1evxt3dXd7XtWtXNm7cyPz586lWrRovvPCCxbFZ32eNGjWidOnS9O/fn507dzJy5Eh5nyu+Lz09PRk8eDDz58/n66+/zrZdbGwsAD169KBx48ZFNLoMYmJi2L59OxMnTuSVV14BkA24999/n4kTJxIUFMTatWvx9vbmgw8+wM3NjbZt2+Lh4cHs2bMZPXo0ZcqUYdOmTfj7+7N8+XLc3Nzkc0ydOpXLly9TuXJl/vzzTw4fPsxHH31E27ZtAWjcuDEdOnTg008/ZcyYMUV+DwQCgeBRQoTMCZxK7dq1Abh9+zZgDK+bOHEi48aNo379+gwdOtQqZG7Hjh3UqVOH48eP06dPH+rUqUOXLl34/vvvuXz5MoMHD6ZevXp06tSJvXv3Wpzvjz/+YPjw4TRp0oTatWvTvn17VqxYgcFgADLC8zZs2EDXrl2pV68eW7du5cknn7RYfQe4c+cONWrUyHHiZi87duygZs2anD59mhdffJE6derQrl07q4l0WloaCxYsoG3bttSuXZunn36affv2WbRp37498+bNY/DgwdStW5dp06YBcOnSJUaMGEHDhg1p0aIFS5YsYerUqQwcOBCAcePG0aZNG/lemJk2bRpdunSx+1pWrFhB165dOXjwID179qROnTo8++yz/Pnnn5w6dYoXXniBunXr0rNnT37//XeL49q3b8/hw4fle9+3b1+OHj1q0f/9+/eZOnUqbdu2pW7dujz//PMcOnTIos2TTz7JypUr6d27N3Xr1pVX0wEGDRokXzPAd999R+/evalTpw4tW7Zkzpw5JCcnW/R37NgxXnzxRerVq0eXLl347bff7LoXH374IV26dJEnusOGDaN3795W7SIiInjmmWcA+PTTT0lKSmLu3LkWxpCZIUOGUL9+fVavXm1XPpT5M3br1i27xpwb7du3Z+XKlcybN49mzZrRoEED3njjDZKSkvjoo49o06YNjRo14rXXXiMmJsbiuCVLljBv3jyaNGlCs2bNmDx5smzcmOnZsycXLlzghx9+sHn+FStWyM9v8ODBcrimXq9n69atPP3009StW5ennnqKRYsWkZaWJh87ZcoUBg8ezIwZM2jYsCHdu3dHr9db9B8bG0udOnVYvHixxfaUlBQaNWrE6tWrSUxM5KWXXrIKFTV7qm7cuAEYPX1t27a1MHS6du2KwWCQQx/Hjx/PRx99ZNFGo9EAyKF1v/zyC15eXrRq1UpuExQURJMmTfjxxx9t3ieBQCAQ2I8wiARO5cqVKwCUK1dO3rZ//368vb1ZvXq1vPqaFZ1OxxtvvMFLL73E6tWr8fT0ZOLEiYwePZqnnnqKNWvWEBISwptvvsndu3eBjNCUgIAAlixZwurVq2ncuDErV65k//79Fv2vWLGCESNGsGDBAjp06EC9evXYvXu3RZtdu3bh5eVF586dc7xGg8GATqez+pd1ImYwGBg/fjzdu3fno48+omHDhixYsICff/4ZMIZfjR07ls8++4yhQ4eyevVqGjRowIQJE6xyKLZu3UqdOnX44IMPeP7554mOjmbAgAHcuXOH+fPnM336dA4cOMCePXvkY55//nnu3btnYYCkpqZy4MABnnvuuRyvMSt3797l3XffZfTo0Sxbtoz4+HjGjRvH66+/zgsvvMCqVauQJIkJEyaQmpoqHxcdHc2bb75Jv379WLZsGR4eHgwfPpyzZ88C8PDhQ55//nmOHz/OhAkTWLFiBWXLlmXs2LFWhumaNWt4+umnWb58OR07duTtt98GjKFi5vDNb775hrFjx1K5cmVWrVrFq6++KodBmY2Nf//9l2HDhuHr68vy5csZNGgQr7/+eq734PLly/zzzz8W749nnnmGf//9l2vXrsnb4uPj+emnn3j22WcB+P7776lVqxalS5fOtu9u3bpx69Ytzpw5k+s4zJ+xrCGn9r4vbbF+/Xru3LnDkiVLGDNmDHv27KFPnz788ssvzJ49m9dff51Dhw6xfPlyi+M+/fRTTp48yfz583njjTf48ccfGTVqlIVhFxoaSv369fnmm29snvuFF16weJYrV66U/54/fz4dO3Zk9erV9O/fny1btlg8S4Djx49z584dVq1axRtvvIFKpbLoPyAggI4dO/LNN99YHHfw4EGSk5Pp1asX5cqVY+bMmVaheocOHUKj0VCxYkVSU1O5desWlSpVsmgTFBSEj4+P/FxCQ0OpXr06AMnJyfz2228sWbKEhg0bytsvXbpEWFiY1VjLly8v9yMQCASC/CNC5gRFgiRJ6HQ6+XVcXBzHjh2TJ/XmVWwwro7OmjVLXjG9efOmVX8Gg4HRo0fLIUPx8fFMmDCBwYMHM3ToUAB8fX3p06cP//zzD6VKleLcuXO0aNGChQsXolQa1wJatmzJ999/z9GjR+nRo4fcf7du3SxyTfr06cOMGTO4ceOGbLzt2rWLHj164OHhkeO1DxkyxOb2atWqWRgkkiQREREhX1OjRo04ePAgP/zwA61bt+a3337j559/ZsmSJXTv3h2A1q1bk5KSwqJFi+jZsydqtfEjXaZMGSZOnCj3vWzZMpKSkti1axehoaEAsrfDTKtWrShVqhS7du2Sw38yTwLzQkpKCjNmzKBNmzYAXLx4kffff5+5c+fy/PPPA8bJ37hx47hy5Qo1atSQj5s5c6Z8vvDwcDp27MhHH33EkiVL2LBhA9HR0URGRlK2bFkA2rZty5AhQ1iwYAE9e/aUn23jxo3l9wIgi3dUrVqVqlWrIkkSixYtonXr1ixatEhuV7FiRYYMGcKPP/7IU089xYcffkhwcDCrV6+WV+4DAwOZMGFCjvfgyJEjANStW1fe1rlzZ2bNmsWePXsYO3YsAN9++y16vZ6ePXsCRk+OOSwqOypUqCC3zZwHlPkzlpqayrlz55g3bx6+vr6yB8qMve9LW/j4+LBkyRLUajUtWrRg586d3Lt3jy+++AJfX18Afv75Z06ePGlxnFKpZMOGDXKboKAgxo4dy88//yy/VwDq1KmT7RhKlSpF1apVAeOzrFmzJhcvXuTLL7/kjTfekMMCW7ZsSUhICJMnT+ann36S76lOp+Odd96hVKlS2V5fnz592LdvH0ePHiU8PBwwft5btGiRraF68OBBdu7cyYABA/D39+fBgwfyvcqKt7e3lWiCJEmEh4eTlpZGQEAAb731lrwvISEh236SkpKyvQ6BQCAQ2IcwiARFwh9//GGVwK1UKmnRogXvvPOOhaBC5cqVLcJHsqNBgwby38HBwYBxkm8mICAAMBpLAL169aJXr16kpaVx5coVrl27xtmzZ9Hr9Wi1Wou+zRN0Mz169GD+/Pns3r2bV199lZMnT3L16lXefffdXMc5a9Ysm8nrtgypzNfk5uZGUFCQHL71+++/o1AoaNu2rcXEt3379nz99ddcuHBBHnfW8R85coQGDRrIxhBA2bJlLc6nVCp57rnn2LRpEzNnzsTT05OdO3fSokWLHCeP2dGwYUP57xIlSgA5Px8AtVotGwZgvEdt2rSRVc+OHTtGgwYNZGPIzDPPPCPnXJgny1nvQVYuX77M3bt3GTVqlMX9bNKkCT4+Pvz666889dRTnDhxgnbt2snGEBgNm6yr9Vm5ceMGfn5++Pn5ydu8vLzo2LEj+/btkw2ivXv30rx5c4tnkxtmoy+rN8fW+6xatWqsXLnSQlAB8va+zErdunVl4xuMz9fLy0s2dMD4fM+fP29xXPv27S3atG/fHrVazR9//GFhEJUtW5aoqChSUlLw9PTMdTzHjh0DsFjUML+eOnUqR48elQ2igICAXN/PLVq0oEyZMuzevZvw8HDu3r3L77//zsKFC222//bbb3njjTdo1KgRkyZNArAKPc1KVhEZnU7H6tWrSUtL46OPPqJ///5s27aN6tWr5xgamZ0YjUAgEAjsRxhEgiKhVq1azJo1CzD+gLu7u1O6dOlsVz3twdaxOU2eUlNTmT17Nrt370an0xEWFkaDBg1Qq9VWEw4vLy+rc3Xt2pWvv/6aV199lV27dlGpUiULgyI7KlWqRJ06dey6pqyTUaVSKY8tNjYWSZIsDI3M3L9/XzYCso4/Ojra5uS3RIkSPHz4UH7dp08f1qxZw7fffkt4eDi///67hfckL+T1+ZjHk3miDUZj15xnEhcXZxFemfk4sDSust6DrJj7nDVrlvzezMz9+/flcwYGBlrsU6vVVtuykpiYaPN6n332Wb7++mvOnTtHiRIlOHr0qKxKBkZjwJZXNDPmHJWshuGXX34p/63RaChZsqS8WJCVvLwvs2Lr2eZ2vwEro0+pVBIYGGglvW/uKyEhwS6DyHx8VqPP/JwSEhLkbfZ8vyiVSnr37s2GDRuYMWMGu3fvxsfHh06dOlm13bhxI++99x5NmzZl1apVct6X+R7Z8uAkJiZaGIZgfF4tW7YEjEZ5+/bt2bRpE/Pnz8fHx8fic2omKSnJqh+BQCAQ5B1hEAmKBG9v73xPvhzF3LlziYyMZOnSpbRo0UKedOUk75uZPn36sHPnTv766y8iIyMZPnx4YQ7XCl9fX7y8vNi8ebPN/eYwKluUKlXK5oQqKirK4nW5cuVo2rQp+/fvJzY2Fh8fHzp27FiwgeeBrAn2YMwbMk/qM4ciZca8LTcjJTNmz83kyZNp2rSp1X6zlHFAQIDVvZMkKdf6WVkn4maaN29OyZIl2b9/PyVLlsTd3d0iz6h9+/asXbuWW7duWRg8//zzjxxaGhkZSXBwsJWR6+zPWG5kFlkAo4crJibGSpI8Li4OhUIhexFzw/ysHjx4YHHPtFotMTExeXpfmOnduzerVq3ip59+Yv/+/XTv3t1C5EKSJObOncsnn3xCz549mT9/voVn29vbm9DQUIt8MTB+5pKSkmRp8++//x5fX1+aNGkit/H19aVcuXKyUV6pUiV++eUXDAaD7B0EuHbtmpDuFwgEAgcgRBUEjw0nTpygWbNmdOzYUTaG/vnnH6Kjo3MNbwHjqm3FihVZuHAhCQkJchJ8UdG0aVOSk5ORJIk6derI/86fP8+qVasswr6y0qRJE06dOmVhTNy/f59Tp05ZtX3++ef57bff2LNnj9UksLBJTU2VRSTMr3/66SfZaG3SpAl//vmnlWLa119/TcmSJXM0CrOGuFWuXJng4GBu3rxpcT9DQ0N5//33ZcGC5s2b89NPP5GSkiIf+/PPP1uFWWalTJkyJCcnWxlOKpWKp59+msOHD3PgwAGL9yPAgAED8PX1Zdq0abJC2u3bt3nppZd48cUXWbFiBceOHWPMmDG5hu25Gj/99JNFUdJDhw6h0+msFiXu3r1LiRIl7AqdBWSDNquq5N69e9Hr9TRq1CjPYy1btizNmzdn8+bNnD171kodcPHixXzyyScMHTqURYsW2Rxry5Yt+eGHHyyuOTIyEpVKJecmbdy4kZkzZ1qEP969e5dLly7x5JNPAsb8vqSkJIvPRnR0NMePH5e9SgKBQCDIP8JDJHhsqFu3Lvv372fbtm1UqVKFc+fOsXr1ahQKhcVkNyf69OnD+++/T5s2bezO+bh48WK2RkXJkiWtwp6yo23btjRp0oSIiAgiIiKoUqUKf/31F8uXL6d169Y5Fv4cNGgQW7duZfjw4XLuygcffIBWq7XKQejSpQuzZ8/mr7/+skjsLiqmTp3K+PHjCQ4O5uOPPyY5OVmuszJ06FC+/vprhgwZwquvvkpAQAC7du3iyJEjzJs3z2L1PCvm0KIffvgBf39/qlevzoQJE3j77bdRqVS0a9eO+Ph4PvjgA+7duyd7X8aOHct3333H8OHDeeWVV4iOjmbp0qUWOUW2ME9UT5w4YSXP/Oyzz7J+/XqUSiVr16612FeyZEmWLVvGuHHj6N27NwMHDqRKlSpMnz6d+fPnc+rUKSpXrsyLL76YtxubBUe9L/PCnTt3GDNmDIMGDeLOnTssXryY1q1b06xZM4t2J0+epHXr1nb3W7VqVZ577jmWL19OSkoKTZo04ezZs6xcuZJmzZrlqa/MPP/887z++utUqVLFIv/t7NmzrF27ljp16tC1a1dOnz5tNR4fHx9eeeUV9u7dyyuvvMLQoUO5evUqixcvpm/fvpQpUwYwSq4PGzaMCRMm0LdvX6Kjo/nggw/w8/Nj2LBhgHEhoGnTpkyaNIlJkyYREBDAihUr8PX15eWXX87XtQkEAoEgA2EQCR4bpkyZglarZenSpaSnpxMWFsaYMWO4ePEi33//vV1yw23btuX999+3WUsmO8wV6W0xaNAguU5QbiiVSj766COWLVvGhx9+SFRUFKGhoQwdOlQ2crLDz8+PzZs3M3fuXCZPnoy3tzf9+vXD09PTKvfD3d2d8PBwLl++bKGQVlTMnDmTefPmER0dTcOGDdm2bZvs+SlZsiTbtm3j/fffZ86cOWi1WqpXr84HH3xAhw4dcuy3WrVq9OzZk61bt/Lzzz+zZ88eXnjhBby9vVm3bh2ff/45Xl5eNGzYkEWLFsm5ShUrVmTLli28++67TJgwgeDgYN58881cBTXKlStHrVq1+PHHH60MourVq/PEE08QExNjM2QzPDycXbt2sWHDBtavX8/du3fx8fGhSZMmtGzZks2bN/P0008zY8YMWrRokZfbK+Oo92Ve6NGjB35+fowfPx4vLy+ee+45K7W++/fvc+7cOf7v//4vT33PnTuXChUq8NVXX7F27VpCQkIYNGgQERERORrKOdG2bVsUCoXV5/3bb79FkiT+/vtvm4bp5s2badasGVWqVGH9+vUsWLCAcePGERgYyJAhQxg3bpzcNjw8nPXr17N8+XLGjRuHWq2mdevWTJw4Uc6NA1i5ciXvvvsuCxYswGAw0LBhQ5YuXSqHCwoEAoEg/ygkeyr7CQQCAD766CM2btzIDz/8YHc4jytw+vRpYmNjLeScdTodTz31lKzEZSY1NZW2bdsSERHB4MGDi2yMK1asYOXKlfz3339Fds7CJjIykv/973/89NNPdouF2ENSUhKff/45jRo1svBcuDLt27enadOmuRqSq1atkiWsna2gtm/fPiZPnsyPP/6YrTiFQCAQCIo/wkMkENjBzp07OX/+PJ9++ikRERHFyhgCYw7KhAkTGDt2LE2bNiUlJYXPP/+chIQE+vbtCxhr2uzcuZPffvsNhUJhUYdJkD86d+7Mhg0b2LZtW7ZFhvODt7e3HE71KJGUlMS2bduYN2+eU42h7777jr///pvPPvuM3r17C2NIIBAIHnGEQSQQ2MG5c+f47LPP6NSpU7GciHbr1o3Y2Fg+/fRTPv74YzQaDfXq1WPLli2ySpVSqeSTTz7B29ubJUuW2JRWFuQNhULBggULGDBgAL17984xz0tg9MC2b9/eoiaRM7h58yabNm2yqCskEAgEgkcXETInEAgEAoFAIBAIHluE7LZAIBAIBAKBQCB4bBEGkUAgEAgEAoFAIHhsEQaRQCAQCAQCgUAgeGwRBpFAIBAIBAKBQCB4bBEqc/lEkiQMBsfrUSiVikLpV5A74t47D3HvnYe4985D3PuiR6lUOL2+lUAgcD2EQZRPDAaJ6Ogkh/apVisJDPQmPj4Znc7g0L4FOSPuvfMQ9955iHvvPMS9dw5BQd6oVMIgEggEloiQOYFAIBAIBAKBQPDYIgwigUAgEAgEAoFA8NgiDCKBQCAQCAQCgUDw2CIMIoFAIBAIBAKBQPDYIkQVBAKBQCAQCIoYvV6PVqt19jAEgkcSjUaDSqWyu70wiAQCgUAgEAiKCEmSuHPnDrGxsUhCdV0gKBQUCggICKB06dJ2Se0Lg0ggEAgEAoGgiLhz5w4xMbH4+gbg7u4OCBlwgcCxSKSlpRETEwtAmTJlcj1CGEQCgUAgEAgERYBeryc21mgM+fr6O3s4AsEji5ubBwCxsbGEhobmGj4nRBUEAoFAIBAIigCtVoskYfIMCQSCwsTd3R1Jwq5cPWEQCQQCgUAgEBQpIkxOICh87P+cCYNIIBAIBAKBQCAQPLYIg0ggEAgEAoFAIBA8tghRBYFAIBAIBAJBntHpdIwcOZTJk6dSvXpNu465fv0aW7Zs5tix34mOjiYoKJhmzcIZMGAw5cqVl9vt2fM1c+bMtDhWrVZTokRJ2rfvyKhREbi7u3P79m169+6Z7flatmzF++8vB6BXrx706PE0I0aMzvvFFhHvvDODffu+sdjm7u5BWFgYL7zwEr169QZs35/MvPbaePr3HyS/vnDhPFu3bubEiePEx8cREhJKhw6dGDhwMN7ePgCcOHGcsWNHWvSjUCjw9PSiSpUqjBw5hiZNmlnsv3//Pps2fcyvv/5CVNRDAgICqV+/Af37D6J69RpyO/NzWrXqIxo1aiyfa8eOPTZV4AwGA6+8MoRJk6ZQo4Z9762CIAwigUAgEAgKkbTbt4n74XskvV7eplQqSKlaCc+WbZ04styRJInYQwdJv3On0M6h0GgI6NARt5IhhXYOQeGwdetmKlasbLcxdPToEaZOnUjTpuHMnDmH0NBS3Lp1ky1bNjFkyADee28RjRs3tThm795v5b+1Wi1///0Xc+bMIj09jYkTp8j75s9fSN269azO6eZW/AQs6tSpy7vvLpJfp6amsmfP17z77hz8/Pxo376jvC/z/cmMt7e3/Pfhw4eYMWManTt3Zf78BQQFBXPhwnlWrFjK0aO/s2rVR3h5ecnt16//hNDQUAAMBok7d26zevUKJk4cz2effUXp0kYD5vz5/xg3bgwVK1ZiypRpVKhQkQcPHvDll9sZMWII06fPpEuXbvm6B0qlkrFjxzF79gw2bfoUjUaTr37sRRhEAoFAIBAUIvc2rSf10kWr7TGHoUrFqqhCSzthVPaRfuc2Dz77tNDPI6WnEzpoSKGfR+A4EhMT2Lx5I2vXbrCrfUJCAjNnTqdTpy5MnfqWvL106TI0atSE6dOnMGPGdD777Ct8fX3l/cHBJSz6KVWqNMePHyMycr+FQeTn52/VtriiVmusrmXUqAi+++5bIiP3WxhEuV1zVNRDZs+eSe/ezzN+/ER5e5kyZalSpSovvtiHL774jMGDh8n7AgICLfotWbIkM2bMplevHvz004+8+OLL6HQ6/ve/ydSoUYtFi5bKstalS5ehbt16rFhRgvnzZ1O7dh3Klg3L131o1Kgxbm5uHDiwl6ef7pWvPuxFGEQCgUAgEBQSqVcuG40hlYqg7j1RKI2pu3E//YAuJob0hw/xdGGDSJ+YCIDK15eATJMwR5F65TJJf51Gn5To8L6LE5Ikka41OO38bholCkXelO927dpBSEgIlStXAYyhXlevXmH9+s1ymzt3btO799MsW/YBN2/eID4+jjFjXrXqS6FQMG7cBHr16sHBg5H07v18judWqdRoNG55Gm9WzCFcs2fP55NPNnL16hUqV67CzJlz+P777/jii8/R63V06tSFiROnoFAoWLt2DX/8cYzw8OZ8/vk29Hodbdu24/XXJ8lhZ7mRmprC++8v5NdffyYxMYGKFSsxdOgrtGvXIddjVSpVnj0lBw7sJy0tlaFDX7HaFxZWjlWrPqR8+Qq59mP2tKnVRtPht99+5ebNG8yZ867NGj8jRoxh586v2LVrB2PHjsvTmDPTqVMXPv10izCIBAKBQCAorsR8dxAA36bNKPHsc/L2tKuXSYyJQRcT7ayh2YUhNQUAdXAJgp9+1uH9x/36M0l/ncaQlubwvosLkiQxZ9NxLtyMc9oYqoX5M31w4zwZRT/++AMtWrSSX/fs+QwRESO4efMGYWHlAIiM3E9ISCiNGzdhz56vqVChIgEBgTb7Cw0tRbly5fnrr1PZGkRarZZjx45w4MBeevR4Jg9XmD1r1qxi2rQZ+Pr6MmXKREaOHEqLFq1YvXotJ0+eYMGCeYSHt6B1a2N469mz/wKwbNkqkpKSmDfvHaZNm8LSpSvtOt+HH67m0qULLF68HD8/P3bv3sH06VP54otdNnNpAJKSkvjqq+1cvXqFUaMi8nR9586doXz5Cvj7B9jcX79+g1z7iIp6yOLFC/H29qFNm6cA+Pvv03h6evLkk9VtHuPh4UGdOnU5ffpUnsablZYtW7NixVJu3LhukWPmaIRBJBAIBAJBIaCLjSXh+DEAAjt0ttinDgwCQBsTU+TjygtSqtFQURZSIVGlu7GavPQYG0TFEYPBwJkz/9K7dx95W4MGDSlbNozIyP0MH25MzI+M3E+3bj1QKpXExcXg4+ObXZcA+PsHEJNlkaBdu5by36mpqbi5udOpU2ciIl6zaPf666+hVFqLJ8+bt4DmzVtabTfTr99AGjZsBMBTT7Xj88+3MWXKNDw8PKlYsRJr167h8uVLskGkUCiYO/c9SpYsCcDEiW8yYcJrXLt2lQoVKuZ4fQC3bt3Ey8uLsmXD8PX1ZeTICBo0aISfX8a9OX36T/m6JUkiNTWVwMAgxo4dZ+VJynx/MrNv33d4enoSHx+Hr69fruOyvCfPy8axwWD0XNav34A1a9bJ123uNycj2t8/kDt3zuTp3FkpV648Go2Gf/75SxhEAoFAIBAUN2J/PAx6PR5VquJRsaLFPk2gcZVcFxtb9APLA4a0VKAwDSJ303keX4NIoVAwfXDjYhUyFxcXh16vI9Bk2IPxOrp37ykbRP/9d44rVy6zYMFiwJiXcu/euRz7NaqfWYprbN68Te7fzc2d4OBgmyFaU6e+Ra1ata22myfw2WH2ZgF4eHgSHFwCDw9PeZu7uzvp6eny63Llylv0aRZyuHTpol0G0cCBg5k4cQJdu3agVq3aNGsWTufOXS2MxerVazJr1hzAKC7g6elFUFCQzf7M9ycrHh7GxYaAgEDu3j2b67gys3jxCkqWLElSUhKffLKRf/75m2HDRlKt2hNym4CAAJKSknLsJyEhPluPoL2oVCr8/PyJiooqUD+5IQwigUAgEAgcjEGrJe6HwwAEduxstV9tmiToXNxDZEg1GUSZJoiORCEMIsA42Xd3s57kuypKpaX3wEz37j1Zt+5Dzp49w8GDkdStW19e1a9fvwEHD0YSFfXQphDAw4cPuH79Gs8+29tiu71egZIlQ/LlQTDnxJjJzTDM2l6vN94DW94pW9SpU4/du/dx7NhR/vjjKPv27WH9+nUsXbpClrR2d3e3+1pya1enTj0OHowkNjbGpnGydOn7eHt7W0iRlypVWg7fe+edeYwf/yqvvz6OjRu3yOerV68hmzZt4Pz5/3jiiSet+k1LS+Pff//mmWees9qXVwwGPQpF4ZZOFYVZBQKBQCBwMAnHjqJPiEcdGIRPg4ZW+9WBAYDrh8yZDRWlRyF5iEyJ2lL6420QFTf8/QPQaDTEZHn/GhXjGvP9999x6NBBevR4Wt7XqVMXAgODWLVqhbztt99+YcCAFzl8+BCrVi3Hy8ub7t17FNl15IcbN66TmJggv/7779MA2ebSZGXt2tWcPn2KNm3a8sYbk9m+fSdhYWEcPvx9oYy3Y8dOeHl5sXHjx1b7rl69ws6dX1oZeZlRqVS89dYslEoF77zztmwEN2sWTpUqVVm1ahn6TCUFzGzevJ60tHSefbZgBpFeryc+Pj5XT19BER4igUAgEAgciLl2D0BAu/YobEw2MkLmXNwgMnuITLk+jkbpblQKe9w9RMWRmjVr8d9/5yyMHoAePZ5m4cL3MBj0dOzYSd7u4+PL7NnzmTx5Am++mcjLL/enXLny1K5dh6lTJwHGsLf8hljFx8cRFfXQartCocw23Cw/JCcnM2vW24wePZaoqCgWLXqPjh07y7V5EhMT0Gp1BAbavo5bt25x4MB+pk6dTtmyYfz77z/cvXuHOnXq5ms8tq4ZjKpwvr6+BAQEMmnSVN55522SkpLo1asP/v7+/P33X6xZs4pq1Z7g5Zf753iOkJAQXnttAvPmvcOXX26nb9+XUKlUzJnzLv/3f2N59dVRDBkynIoVKxEVFcWuXTvYv38P//vf27l6sP788wTXrl2x2BYWVk4+7sKF8+j1epvhkI5EGEQCgUAgEDiQlAvnSbt+DYVGg79JkSkratNkSZ+QgEGrRVnIRQfzizmHSOFROAaRCJkrvrRp0459+76x2t6uXQcWLnyPtm3bWUlRN2zYiI0bt7JlyyZmzpxOVFQUAQGBdOnSDZVKxYoVS4iLi2XQoKF5Ho/ZqMqKp6cnhw//muf+siM0tBRPPPEEo0cPR6VS0aVLNyIiMmSlFy9exMmTx9m1a6/N4ydNmsLy5UuYOXM6cXFxlC5dhoiIcXTrlj/PWI8e1iG5AC1btuL995cD0KVLN0JCQti69RMmT36dxMQESpUqTc+ez9Cv30CLnKnseOaZXnz77X7WrFlJmzZtKVWqNJUqVWbTpk/ZsmUTixa9x/379/D19aVhw8asXbuR6tVr5Nrv7NkzrLYNHz5SDuE7ceI4VapUzXctI3tRSJIkFeoZHlH0egPR0Tknk+UVtVpJYKA3MTFJ6HTOS658HBH33nmIe+88xL0vHG6vXkniieP4tW5DqUzFDjOjUik4N/IVJK2WSvMXoinkcJD8cvfjtcT//islnu9LUNfuDu9fn5TEpf8bC0C1NetsetMcSVCQNyqV87IFUlNTuXTpMiVKlJLruhRX4uLieO65nqxa9SE1atR0SJ9nz57h4sXzhV5zJr+sXbuGvXu/ydbYAWOI14gRQy3qMQnyT//+fenb9+V8hd6lp6fx8OFdqlSpLItMZIdTc4iOHj3Kk08+afNfhw5GWcGbN28yatQoGjZsSKtWrVi6dKlVrOLWrVvp0KEDdevWpV+/fpw5YynxZ08fAoFAIBAUFG1UFIl/ngQgsEOnbNspFArcg41hPK6sNCerzBWShyizep3wEhUv/P396ddvANu2bXVYnzVq1HRZY8hetmzZRLt27Z09jEeCo0ePoNVq6dGjZ6Gfy6khcw0aNOCXX36x2Hbq1Clee+01IiIi0Gq1DB8+nIoVK/LZZ59x/fp1pk2bhlKpZNw4o3ty586dLFiwgNmzZ1OzZk0++ugjhg4dyv79+wkKCrKrD4FAIBAIHEHSv3+DwYBH1Wq4Z5LztYVbUBCpd++5dB5RYecQKdRqUKlAr8eQlobK27tQziMoHAYPHsYrrwzmzJl/qVmzlrOH4xL06zcQjYuGwBYnDAYDa9as5O23Z6FWF/79dKpB5ObmZqEakZyczPz583nuuefo06cPe/bs4fbt22zfvh1/f3+eeOIJoqKiWLBgAaNHj8bNzY01a9YwYMAAnnnGWLF43rx5dOzYkS+++IJRo0YRGRmZax8CgUAgEDgCc4FRTVBwrm3dTIneriy9XdgqcwBKNzcMKSlCaa4YotFo2LTpU2cPo8gYMWK0hTy1LYQx5BiUSiUbNmwpsvO5lKjCmjVrSElJ4c033wTg+PHj1KpVC39/f7lNeHg4iYmJnD17lrCwMK5evUrz5s3l/Wq1msaNG/PHH38watSoXPuoV69evserVjs24tAc1+zM+ObHFXHvnYe4985D3HvHo9DrAFC6aXL8jVCplLiZQub08bEO/z1xFJIpZE7t7VVoY1S6e2BISUGh07rsfRAIBI82LmMQRUdHs3HjRt544w0CAgIAuHv3LqVKlbJoZ65gfOfOHVk3vXTp0lZtzp07Z1cf+TWIlEoFgYGF49r38yucAniC3BH33nmIe+88xL13HAka44Te08cz19+IBJNBpEyKL7TfkwKTng5AQIkAfAtpjGovD3Sx4O2mwN9V74NAIHikcRmD6NNPP8XX15cXX3xR3paamoqfn59FO3dTAmZaWhopKSkAVmFv7u7upJnc/Ln1kV8MBon4+OR8H28LlUqJn58n8fEpcuVjQdEg7r3zEPfeeYh773iS443qo+kGBTEx2SuRqlRK3Exhdcn3H+bY1pnoTL+ziVoJXWGNUWP8DY97GIuhkO+Dn5+n8IgKBAIrXMYg2rVrF7169bKQxfPw8CDdtDplxmzEeHl5yW1ttfH09LSrj4JQWDK1er1BSOA6CXHvnYe4985D3HvHoU8z/t5ISlWu99SsMqeNjnHZ+28wGUSS2r3QxqgwyU/rklNd9j4IBIJHG5dYJjl37hw3btzg6actqx2XKlWK+/fvW2wzvw4NDZVD5Wy1CQ0NtasPgUAgEAgchaQz5hAp7EisdgsyFmfVxcbgiiUBJZ1Ovp7M8tiORmGK8hCy2wKBwFm4hEF0/PhxgoODqV69usX2Jk2acObMGRITE+VtR44cwdvbm+rVqxMcHEylSpU4evSovF+n03H8+HGaNGliVx8CgUAgEDgKSasFQGmXQRQkH2NIcr2QOUMm1bfCqkMEGcaWUJkTCATOwiUMojNnzvDkk09abe/YsSMlS5Zk/PjxnDt3ju+++47FixczbNgwOW9o2LBhbNiwgZ07d3Lx4kX+97//kZqayvPPP293HwKBQCAQOAKzQaSwo26G0s0NlY8PgEvWIjLXIFKo1cZ6QYWEwmQQCQ+RQCBwFi6RQ/TgwQNZWS4z7u7urFu3jlmzZtG3b19TVeR+REREyG369u1LQkICS5cuJTY2ltq1a7NhwwaCTCtv9vQhEAgEAoEjkHQmg8jOWiTqwED0iYnoYmNyLeRa1BhSjQaKohDD5SCj6KswiIofOp2OkSOHMnnyVKpXr2nXMdevX2PLls0cO/Y70dHRBAUF06xZOAMGDKZcufJyuz17vmbOnJkWx6rVakqUKEn79h0ZNSoCd3d3bt++Te/ePbM9X8uWrXj//eUA9OrVgx49ns61lpAzeeedGezb943FNnd3D8LCwnjhhZfo1as3YPv+ZOa118bTv/8g+f6sWvURjRo15sSJ44wdOxKVSsWePd8SGBhocVx6ejrdu3ckMTGRHTv2UKZMGbvHZObUqZNs27aVv//+i+TkJMqUKUv37j158cV+VnWa/v33Hz75ZCOnT/9JUlISISGhtG7dlgEDBhEcXEJut3TpIkJDS/HyywPsvpd5wSUMorVr12a7r0KFCqxfvz7H44cPH87w4cML1IdAIBAIBAVF9hDZaRBpAgNJu3EDXWxsIY4qf5hrEJkNlsJC6e5mOp8wiIobW7dupmLFynYbQ0ePHmHq1Ik0bRrOzJlzCA0txa1bN9myZRNDhgzgvfcW0bhxU4tj9u79Vv5bq9Xy999/MWfOLNLT05g4cYq8b/78hdSta11Kxc2tcA36wqBOnbq8++4i+XVqaip79nzNu+/Owc/Pj/btO8r7Mt+fzHh75yxhr1Ao+PHH7+nVq4/F9iNHfiPJRgivvWPavv0zli1bzEsvvczQoa/g6+vLX3+dZvnyJfz55wkWLlyKUqk0jf0b5s2bTffuPVm4cClBQcFcvnyR9evXcfDgAZYuXUXVqtUAGD58FP36PU+rVm0sDGdH4RIhcwKBQCAQPAoYZIPIvvVGdYBJWCHGdUPmCjN/CDJU5oSHqHiRmJjA5s0bGTBgkF3tExISmDlzOp06deHddxdRv35DSpcuQ+PGTVmyZCXh4c2ZMWM6CQkJFscFB5eQ/5UqVZpOnbrQtWs3IiP3W7Tz8/O3aGv+5+vr67BrLirUao3FNZQtG8aoURGUK1fe6rptXXNwcAk8PHKuL9ekSTMOHfrOavt3331L/foN8jWmCxfOs2zZYsaNG89rr02gevUalC0bRrduPZg37z1+/fUXvvvOaMBdv36Nd9+dw8iRo5k27W1q165DmTJlaNWqDWvWrKNMmTDefvt/6PV6AHx9fenUqSvr12fvRCkIwiASCAQCgcBByCpzduQQgTFkDlw0h8hkoCg9CjtkzmQQPcaiCpIkIWnTnPcvHyqHu3btICQkhMqVqwDGUK9hwyyNozt3btO8eSOOHTvKwYORxMfHMWbMq1Z9KRQKxo2bQHR0FAcPRuZ6bpVKjUZTsDzw27dvEx7ekIMHIxk06GXatAlnyJD+XL16hfXr19KtW0c6d36KhQvny/dn7do1jBw5jPXr19KlS3s6dmzD7NkzSEpKzOVsGaSmpjB37jt0796JNm3CGTToZQ4fPmTXsSqVyirkLL906NCJkydPEJvpuyc1NZVffvmJjh272N1P5jHt3r0TX18f+vTpa9WuQYNGrFy5hubNWwKwY8eXeHl506/fQKu2bm5uRES8xuXLlzh27Ii8vVOnLhw8GMmDBw/sHp+9uETInEAgEAgEjwL5CZkDF/UQFVnInEll7jH1EEmSRMLOOejvXnDaGFSlquH73HQUCoXdx/z44w+0aNFKft2z5zNERIzg5s0bhJny4SIj9xMSEkrjxk3Ys+drKlSoSEBAoM3+QkNLUa5cef766xS9ez9vs41Wq+XYsSMcOLCXHj2eycMVZs+aNauYNm0Gvr6+TJkykZEjh9KiRStWr17LyZMnWLBgHuHhLWjdui0AZ8/+C8CyZatISkpi3rx3mDZtCkuXrrTrfB9+uJpLly6wePFy/Pz82L17B9OnT+WLL3ZRpkwZm8ckJSXx1VfbuXr1CqNGOSYHvkGDhgQGBvDDD4flHKBff/2ZMmXKUrFipVyPtzWmc+fOULNmbdTZiLBkDof8++/T1KxZK1sDr27deri7u3P69CnZiKpRoyb+/gH89tsvPPvsc3m63twQBpFAIBAIBA4iL7LbkClkzgVziGSVOREyJ8iCwWDgzJl/6d07I/+kQYOGlC0bRmTkfoYPHwkYDaJu3XqgVCqJi4vBxyfn8DV//wBiYqIttrVr11L+OzU1FTc3dzp16kxExGsW7V5//TU5NyUz8+YtkCfUtujXbyANGzYC4Kmn2vH559uYMmUaHh6eVKxYibVr13D58iXZIFIoFMyd+x4lS5YEYOLEN5kw4TWuXbtKhQoVc7w+gFu3buLl5UXZsmH4+voycmQEDRo0ws8v496cPv2nfN2SJJGamkpgYBBjx46jXbsO2d6fzOzb9x2entmHzSkUSp56qgPff/+dbBB99923dOpk2ztkz5ji4+MpWzYs13tgbptTLpBSqcTPz8/CgwVQqVJl/vnnL2EQCQQCgUDgquQ1ZE7jyiFz5hyiwlaZ83i8DSKFQoHvc9NBl+68Qajd8uQdiouLQ6/XERgYJG9TKBR0795TNoj+++8cV65cZsGCxQAEBARy7965HPuNj48jJCTEYtvmzdvk/t3c3AkODkalUlkdO3XqW9SqVdtqu9lwyY6wTOqOHh6eVvk37u7upKdnPJty5cpb9GkWcrh06aJdBtHAgYOZOHECXbt2oFat2jRrFk7nzl0tjMXq1Wsya9YcwGgYeHp6yerJWTHfn6x42LGQ0bFjJ8aOHU1cXCwajRu///4rr702njt37li1tWdMAQGBxMXF5XpeY9sAixqhWZEkicTERCuPYmBgIFFRUXadIy8Ig0ggyIboyP1o798jZMDgPP1QCASCx5e8hsyZc4j0CQlIOl2h1vvJKxmiCjknZxeUxz1kDoyTfTTFRw1NqTT+JhoMBovt3bv3ZN26Dzl79gwHD0ZSt2592QtQv34DDh6MJCrqoYWcspmHDx9w/fo1nn3WUsLZXkWxkiVD8qU+ljW8K7ff+6zt9XrjPbDlnbJFnTr12L17H8eOHeWPP46yb98e1q9fx9KlK2jSpBlgNMLsvZaCKK7Vq9eAoKAgfvzxB9zd3alSpSplypS1aRDZM6Y6deryzTe70Ov1No3WGTOmUbduffr0eYF69Rqwd+/XaLVam2FzZ878S0pKCnXr1rfYbjAYCmVOJkQVBAIbSJJE1K4dxP34A+m3bzl7OAKBoJgg5VFlTuXjAyoVSBI6O1dWiwqzgVLYHiI5ZO4xFlUobvj7B6DRaIjJkvtWunQZGjVqzPfff8ehQwfp0eNpeV+nTl0IDAxi1aoV8rbffvuFAQNe5PDhQ6xatRwvL2+6d+9RZNeRH27cuE5iYoYS3t9/nwbgySer23X82rWrOX36FG3atOWNNyazfftOwsLCOHz4+0IZb04oFArat+8gP6/swuXspWfPZ0hKSubLLz+32nfixHEiI/fLcuC9ez9Pamoqn3yy0aqtTqdj9eoVVKhQkWbNwi32RUdH5+r1yw+usxQlELgQUlqaPLHRPnyIu50xsQKB4PFGLsxqZ8icQqlEHRCALioKXWwMmuDgwhxenpBFFQo5h0hWmXuMPUTFkZo1a/Hff+csjB6AHj2eZuHC9zAY9HTs2Ene7uPjy+zZ85k8eQJvvpnIyy/3p1y58tSuXYepUycBxrC37EQXciM+Po6oqIdW2xUKZbbhZvkhOTmZWbPeZvTosURFRbFo0Xt07NiZ0qWNggiJiQlotTqrgqdmbt26xYED+5k6dTply4bx77//cPfuHerUqZuv8di6ZjDWX7JHcrxDh85ERIxAo9EwadLUfI3BTKVKlRk1KoJlyxZz//59unbtjru7O3/8cYwPP1xF27btZKOrTJmyvPXWLGbNeot79+7y7LO9CQ4O5urVK2zYsI7r16+zbNkqC0+TwWDg4sXzhWI0C4NIILCBPpOEpi6bLxuBQCDIiiGPIXNgFFbQRUW5nNJcRg6RUJkTWNOmTTv27fvGanu7dh1YuPA92rZth7e3j8W+hg0bsXHjVrZs2cTMmdOJiooiICCQLl26oVKpWLFiCXFxsQwaNDTP4zEbVVnx9PTk8OFf89xfdoSGluKJJ55g9OjhqFQqunTpRkTEOHn/4sWLOHnyOLt27bV5/KRJU1i+fAkzZ04nLi6O0qXLEBExjm7d8jfJ79Gjs83tLVu24v33l+d6fJ06dQkOLkGZMmUd4nkZNGgIFStWZPv2bezd+zWpqamULRvGsGEj6NOnr4WB0759R8qVK8+WLZt48803iIuLJSQkhFat2jJ37ntWoZXnz58jOTmZli3bFHicWVFI+RGfF6DXG4iOtq7kWxDUaiWBgd7ExCSh0xlyP0DgMLLe+9RrV7k+eyYAgV26UvKFl5w7wEcY8b53HuLeOxbJYODCyGEAVF6yHLWvX7ZtM9/76ytXkHj8D0q+1J/ATCvqzubWymUknfqTkEFDCGjzVKGdRxsTw5VJE0ClotqadYWasxkU5I1K5bxsgdTUVC5dukyJEqVwcys+OUO2iIuL47nnerJq1YfUqFHTIX2ePXuGixfP8/TTvRzSn6NZu3YNe/d+k62xA6DX6xkxYijr128uwpE9Hixa9C4JCQnMmjXXrvbp6Wk8fHiXKlUq5yoyIXKIBAIb6DMpn2gLQc1EUHRIBgOSQUz2BYWPWWEO7JfdhszS24+rh8hUYFOvt7iHAtfG39+ffv0GsG3bVof1WaNGTZc1huxly5ZNtGvX3tnDeOSIi4vl0KHvZEl3RyMMIoHABpYhc8IgKq5IBgPX583m+uyZwigSFDrmvEOwP4cIQB0QALhecdYMlblCNogyeUpE2FzxYvDgYVy7doUzZ/519lBchn79BjJw4BBnD+OR4+OP1zJgwCDKl69QKP2LHCKBwAaGzB6ihyKHqLiiT0ok7eoVALRRD3ErGZLLEQJB/jELKqBQGJXj7ETtorWIikxlTq023i+9HkN6Gip8cj9I4BJoNBo2bfrU2cMoMkaMGM2IEaNzbGNLQlpQcF5/3XaOmKMQHiKBwAb6pIz8MH1CPIZ0JxbME+QbC8P2wQMnjkRQEAxpaVyb9Ra3Vi5z9lByJHMNorzkwbhsyFwRqcyBEFYQCATORRhEAoENMofMgVCaK67oEzMMW2EQFV+S/ztL2o0bJJ36Uw7jckVkgygP4XKQySCKicGVdI6KKmQOMktvi8UngUBQ9AiDSCCwQWZRBRDCCsWVzIat9sF9J45EUBCSz56V/3bl52gWBLC3KKsZc8iclJ6OISXF4ePKD5IkyXWBFIUsqmA8h9kgcl2DVyAQPLoIg0ggsEFmzwIIg6i4os9UTdyVJ9KCnEk5d0b+O/2+6z7H/NQgAlC6uaH0MlZvd5WwOUmnA70eKPwcIsgQVhDFWQUCgTMQBpFAYAODybOgDjRWtxYhc8UTvcghKvboEuJJu3FDfq11YYPIHDKnzGPIHLie0pyUKTSxSHOI0oVBJBAIih5hEAkENjBPpN0rGOUdtcIgKpZYGkT3XSo/Q2AfKefOWbx2ZU9ffkPmwPWU5syhawo3NxTKwp8qZITMCYNIIBAUPUJ2WyCwgTn3xKNCRZJO/SlC5oopmXOIDCkpGJKSUPkISd/iRPJZY7icys8PfXw86ffvOXlE2SPlM2QOLIUVXIGMoqyFHy6X+TxCZa54odPpGDlyKJMnT6V69Zp2HXP9+jW2bNnMsWO/Ex0dTVBQMM2ahTNgwGDKlSsvt9uz52vmzJlpcaxaraZEiZK0b9+RUaMicHd35/bt2/Tu3TPb87Vs2Yr3318OQK9ePejR4+lcpbOdyTvvzGDfvm8strm7exAWFsYLL7xEr169Adv3JzOvvTae/v0Hye2OHDmZbdvw8IbUrFmbtWs3oMpSMmDMmBGULl2Gt9+eJW/T6bR89dUXREYe4MaNa6Snp1OmTFmeeqo9/fsPxMfH1+ocR48e4f/+L4K2bdvx3nvvW+2XJInt2z9jz57dXL9+DbVaQ7Vq1ejb92Xat+8IgMFg4JVXhjBp0hRq1LDv/WYvwiASCLIg6fUYkpOBDA+RCJkrnliJYzy4LwyiYkbyOaOggl/L1sTs3+vaHqJ8qswBqAMDANDFxTpwRPnH7KkpinA5yJxDJFTmihNbt26mYsXKdhtDR48eYerUiTRtGs7MmXMIDS3FrVs32bJlE0OGDOC99xbRuHFTi2P27v1W/lur1fL3338xZ84s0tPTmDhxirxv/vyF1K1bz+qcbm5FY9Q7kjp16vLuu4vk16mpqezZ8zXvvjsHPz8/2UAAy/uTGW9v7zyd88yZf9i6dTODBg3NsV1KSgqvvTaa+/fvM2zYKzRo0AiNxo1z586wdu0afv75R9at24RHlu+OvXu/pkKFivzyy888ePCAkiVLWuxfu3YNu3fvZMKEidSoUZO0tDQOHfqWadPe5K23ZtG9e0+USiVjx45j9uwZbNr0qUNrPomQOYEgC/rkDEEF93Imgyg2Vg6HERQfDFYGkcgjKk5oo6LQ3r8HSiX+rVoDoIuOlsULXA1zYdZHyUNUFApzAAoPoTJX3EhMTGDz5o0MGDDIrvYJCQnMnDmdTp268O67i6hfvyGlS5ehceOmLFmykvDw5syYMZ2EhASL44KDS8j/SpUqTadOXejatRuRkfst2vn5+Vu0Nf/z9bX2Vrg6arXG4hrKlg1j1KgIypUrb3Xdtq45OLgEHh6eeTpn2bJhrFv3IVeuXM6x3apVy7l69Qpr126gV68+VKhQkTJlytC+fUdWrfqIO3fusGfP1xbHJCQk8OOPhxkyZBienh58/fVOq36/+uoLBgwYRMeOnSlbNozKlaswYsQYOnToxGefZRT/bdSoMW5ubhw4sDdP15cbwiASCLJgnkQrPT1RBwQYJzeShDY62skjE+QVvSyOYZxsah8Kg6g4YQ6X86hYCU1IqDHPRJJc1mObX5U5yFycNdaRQ8o3RR4y5/Z4h8xJkkSaLs1p//KTX7lr1w5CQkKoXLkKYAz1GjbM0ji6c+c2zZs34tixoxw8GEl8fBxjxrxq1ZdCoWDcuAlER0dx8GBkrudWqdRoNG55HnNmbt++TXh4Qw4ejGTQoJdp0yacIUP6c/XqFdavX0u3bh3p3PkpFi6cL9+ftWvXMHLkMNavX0uXLu3p2LENs2fPIClL7cKcSE1NYe7cd+jevRNt2oQzaNDLHD58yK5jVSqVQ70imRkwYBBly4bxzjtvozcpTGYlOTmZPXt28/LLAwgNLWW1PygoiM2bP5XD+sx8++0BtFot4eEtadWqDV9/vcvqHEqlguPH/yA1S62511+fbOEtA+jUqQuffrolP5eZLSJkTiDIgllyW+Xjg0KhQB0cjPbuXXRRD3ELCXHy6AR5wRwy51GxMokxJ1xasllgjdkg8qpRE4VCgVtICGk3bpB+/x5upUo7eXTWZITM5UNUwcU8RFJRh8yZRRUeQ5U5SZJY+McqLsVeddoYqgRUZFKTsSgUCruP+fHHH2jRopX8umfPZ4iIGMHNmzcICysHQGTkfkJCQmncuAl79hhDpgJM7/WshIaWoly58vz11yl6937eZhutVsuxY0c4cGAvPXo8k4crzJ41a1YxbdoMfH19mTJlIiNHDqVFi1asXr2WkydPsGDBPMLDW9C6dVsAzp79F4Bly1aRlJTEvHnvMG3aFJYuXWnX+T78cDWXLl1g8eLl+Pn5sXv3DqZPn8oXX+yiTJkyNo9JSkriq6+2c/XqFUaNinDIdWdFo3HjrbdmMWLEED75ZCNDhgy3anPmzD+kpqbSpEmzbPspWzbMatuePbtp2LARgYGBdOzYmQMH9vHrr7/Qpk1buc2gQUNZtmwxPXp0pkmTpjRo0JBGjZpQtWo1q/5atmzNihVLuXHjukXeWUEQBpFAkAWzV0Hpbcw10QSXQHv3rhBWKGZIkoQ+yWjcelSqROKfJ4SHqBghSRLJ5zIMIgBNSChpN26gve+azzFDZS7vK7gqP2NYjyEpEUmS8jQxLQzMoWtFZRAJlbnihcFg4MyZf+ndu4+8rUGDhpQtG0Zk5H6GDx8JGA2ibt16oFQqiYuLsZlsnxl//wBiYiyjMdq1ayn/nZqaipubO506dSYi4jWLdq+//hpKG4qI8+YtoHnzllbbzfTrN5CGDRsB8NRT7fj8821MmTINDw9PKlasxNq1a7h8+ZJsECkUCubOfU/OgZk48U0mTHiNa9euUqFCxRyvD+DWrZt4eXlRtmwYvr6+jBwZQYMGjfDzy7g3p0//KV+3JEmkpqYSGBjE2LHjaNeuQ7b3JzP79n2Hp2fewuZq1qzFgAGD+Pjjj2jdui1VqlS12B9tipTJatQOGPAit27dlF/Xq9dANhAvXbrI2bNnmDJlOgDh4c3x8/Nn166vLAyil18eQMWKldix40uOHTvCDz98L4/prbdmUalSZbltuXLl0Wg0/PPPX8IgEggKC7NXwZx8rwkuAQjp7eKGISVFLizpYfoideUaNgJL0u/cQR8Xh0KjwaOKMSRHU9LoodW6qNKcXIcoPwaRaQFG0umQ0tNlA8FZOC9k7vETVVAoFExqMpZ0vfOu3U3llicjPC4uDr1eR6CpVh8Yr6N7956yQfTff+e4cuUyCxYsBoyT6Hv3zmXXJQDx8XGEZInE2Lx5m9y/m5s7wcHBVkpoAFOnvkWtWrWttmdN3s+K2ZsF4OHhaZV/4+7uTnp6xrMpV668RZ9mIYdLly7aZRANHDiYiRMn0LVrB2rVqk2zZuF07tzVwlisXr0ms2bNAUCpVOLp6UVQUJDN/sz3JytZRQ3sZfjwUfz880/Mnj2Ddes2Wezz9w8AjM8pM4sWLUVr+v5btWo5cXEZ+7/5ZjdqtVo25NRqDe3ateebb3Zz585tSpfO8Io1b96S5s1botNpOXPmDL/88hNffrmd8eNf5csvd8vhgiqVCj8/f6IcuFAtDCKBIAtmD5F5gqIODgaE0lxxw/wcFW5uuJnCEHQx0Ug6Xb5CmgRFi9k75Fm1GkpTroDGNFFyVaW5goTMKdzcUKjVSDod+qTEIjNEsqOoPURKj8c3ZA6Mk313dfFRQ1MqjcaTwWCw2N69e0/WrfuQs2fPcPBgJHXr1pdX8OvXb8DBg5FERT0k2LTQmJmHDx9w/fo1nn3WMv/EXg9AyZIh+fIWqLN8XnMzDLO21+uN98CWd8oWderUY/fufRw7dpQ//jjKvn17WL9+HUuXrpBD0dzd3e2+Fkd5SMy4uRlD5155ZQibN2+02FejRk3c3Nw4efIEtWvXkbeXyhTC7OXlLRtEOp2WyMh96HQ6unfPUMaTJAmDwcCuXTsYM+ZVLlw4z44dXzB+/ETc3d1RqzXUrVuPunXrUa9efd544/+4ePGChdS2waBHoXCcFIIQVRA8dugTE7n3ySbSbtzIdj9k8hCVMHmIHgqDqDhhyPQcVX7+KNzcjOIYwrAtFmTOHzLjZvIQuWouWEFU5hQKBUqTTK4hKSmX1oWPIdVomBSZypxZdjtVqMwVB/z9A9BoNMRkyXkrXboMjRo15vvvv+PQoYP06PG0vK9Tpy4EBgaxatUKedtvv/3CgAEvcvjwIVatWo6Xlzfdu/cosuvIDzduXCcxMUMJ7++/TwPw5JPV7Tp+7drVnD59ijZt2vLGG5PZvn0nYWFhHD78faGMNz/UqFGTgQMHs2HDWm7fviVv9/Pzo0ePp9m2bQv3bXwPGwwGHmRasPrll5+JiYlh0qSpbN68Tf73ySefUaVKVfbs+RqdKdR4586v+OmnH6z69PHxRaFQEBiYEaan1+uJj4/P1fuXF8QyqeCxI+a7SOJ+PIwhOYnSNpITzZMRlWlyogkyGUTRIoeoOCEbtt5GcQxNyRDSb91E++A+bjbUcQSug2QwkPKfMbTGM1N9E01IKGBUC5QMBhR2rsgWFQUpzArG7xx9XJyc++ZM5JC5IhZVkB5TD1FxpGbNWvz33zkLowegR4+nWbjwPQwGPR07dpK3+/j4Mnv2fCZPnsCbbyby8sv9KVeuPLVr12Hq1EmAMewtO9GF3IiPjyPKxoKXQqHMNtwsPyQnJzNr1tuMHj2WqKgoFi16j44dO8uhX4mJCWi1OosJfGZu3brFgQP7mTp1OmXLhvHvv/9w9+4d6tSpm6/x2LpmMNZfyiw5/vvvv1q1qVKlmlWIopnhw0fy888/cunSRYvt//d/r3P16hWGDOnP0KHDady4KW5ubpw58y/btm3h7Nkzcg7Znj1fExpail69eluFOb788gDmzJnJTz/9QPv2HenatTvz58/m7t07tGrVBpVKzcWL51mzZhXdu/e08EJduHAevV5vM0QyvwiDSPDYkXL+PJB9TpAsqmDyEKlNHiJdTAySXo/CRuyywPWw8vSVLGkyiFwzIV+QQdr1axiSk1F6euJRsaK8XR0YKIeV6aKj0JRw3OqgI5BFFfJRmBUywnT1eZDwLSwkc8hcEXmIZJW5xzCHqLjSpk079u37xmp7u3YdWLjwPdq2bYe3t2Uh7IYNG7Fx41a2bNnEzJnTiYqKIiAgkC5duqFSqVixYglxcbG5Fge1hdmoyoqnpyeHD1sbA/klNLQUTzzxBKNHD0elUtGlSzciIsbJ+xcvXsTJk8fZtct2nZxJk6awfPkSZs6cTlxcHKVLlyEiYhzduuXPM9ajR2eb21u2bMX77y+XX0+Y8JpVm+nTZ9Kzp221Po1Gw1tvzWL48MEW2z08PFm16iO++WY3Bw7sZd26j0hOTiI0NJRGjZowZcp0nnjiSaKiovj9998YMWKUzZyvLl26sWbNSnbs+JL27TsyffpMvvpqO/v372XDho/R6bSEhZXjmWd68dJL/SyOPXHiOFWqVLWpaJdfhEEkeKwwaNNJvXwJINu6Qpk9CwBqf39QqUCvRxcbi8aUUyRwbazUAuWEfNcMtxJkYA6X83yyuoUXSKFUoilRkvS7d9A+eOByBlFB6hABcsicS3iIZNntoslrESpzxY+ePZ/h448/4uzZMxa5HR4ennz//c/ZHhcWVk5WHMvK2bNnuHjxvNx/dpP1zJQpU4YjR07aNebMRoqt40aMGM2IEaOzPQaM4a0jRoxhxIgxNs8xbdrbjBiRvUHn7e3D1KlvZbv/7bdnZbsvM/beH3vaZXf/qlevwa+/HrParlQqefbZ53j22eey7TM4ONjmsWY0Gg179nwrv1ar1bz4Yj9efLFftseY2bfvG/r2fTnXdnnBteINBIJCJvXKFXkVVx8XJ/+dmayeBYVSicbkbhf5J8UH+Tn6ZniIANKF9LbLI+cPZQqXM2MWVkh3QaW5AofMeblSDlERh8y5iZC54oa/vz/9+g1g27atDuuzRo2aPP10L4f15wy2bNlEu3btnT2MR5ajR4+g1Wrp0aOnQ/sVBpHgsSLlwvmMF5KELi7Wqk1WlTkAtUkRRyjNFR+yevrMCfkiZM61kfR6Ukwx617VrZOUZaU5VzSI5JC5/AVfqFzJQ5RaxCFzHhmiCpIkFck5BQVn8OBhXLt2hTNn/nX2UFyGfv0GMnDgEGcP45HEYDCwZs1K3n57Fup8hiZnhwiZEzxWpJz/z+K1LjpGrjMEJilI2UPkLW/XBJcgBURx1mKErRwiMEo2u0LhS4Ft0m7dREpLQ+npiVuZslb7M0IfXc+wLUgdIsgUMpfo/Bwis+x2UdVDMqvMIUlIOi0Kk9S6wLXRaDRs2vSps4dRZNgKqcuKJp+ff0HuKJVKNmzYUjh9F0qveWTXrl10796dOnXq0KNHD/bv3y/vu3nzJqNGjaJhw4a0atWKpUuXojcVWzSzdetWOnToQN26denXrx9nzpyx2G9PH4JHH0mvJ+WiceVZZSqApo2xNHCk9HR5ldc8kYZM0tvCQ1RsMFjVkyoBCgVSWhr6hIScDhU4kdRLxhw/j0qVbarIuZmU5h7JkDnTe9U1QubMOURFK6oAj2dxVoFA4FycbhDt3r2badOm0b9/f/bu3UvPnj15/fXX+fPPP9FqtQwfPhyAzz77jJkzZ7Jt2zZWrVolH79z504WLFjA//3f/7Fjxw7CwsIYOnQo0aaEeXv6EDwepN24jpSWitLLC6+atQDQZRFW0JtrC6hUFvU31EGm4qwPhYeouJA1h0ip0aA2yaC6amFPAaRcNi5aeFSpanO/7CEyefpcCbkOUb5V5swhc873EBW1ypxCpZJDDYWwgkAgKGqcGjInSRLLli1j0KBB9O/fH4AxY8Zw/Phxjh07xq1bt7h9+zbbt2/H39+fJ554gqioKBYsWMDo0aNxc3NjzZo1DBgwgGeeMSpozJs3j44dO/LFF18watQoIiMjc+1D8HhgDpfzrFoNtUkpLqtBpMsUZpU5pMqsLKeNFh6i4oKtXDBNiZLooqPRPriPZzYTboFzMXuIPKtUsblfU8Lk6UtPRx8XhzogoAhHlzMF9RC5isqcJElFrjIHxrA5SacTBpFAIChynGoQXblyhVu3bvH005ZFvT7++GMAZs6cSa1atfD395f3hYeHk5iYyNmzZwkLC+Pq1as0b95c3q9Wq2ncuDF//PEHo0aN4vjx4zn2Ua9evXyPX612rINNpVJa/C9wLKkmQQXv6tXl8Ax9bAxqtTLjnicnA6D28bF4vh6hxlVpXVQ0KiUuVxCyOFNY73uzh8jN309+lu6hoaSc/w991EOHf36LI672naOLj5fFEnyqVUNl6xmp3dAEB6N9+BBD9APUJRxXcLGgSFpjuK3awy3X95ete+/mbwzlNSQnOfX9aUhLA5P3zc3HG2WWsUiSxJW465TyDsFL4+mw8yo93DEkJ6HUp4vPp0AgKFKcbhCBserv8OHDOXPmDGFhYYwZM4b27dtz9+5dSpWyrChvrqh7584d1Cb3eunSpa3anDtnrHKeWx/5NYiUSgWBgd65N8wHfn6O+4ERGJEMBs5fvABAqcb10cbFcRcwxMVaPEeN3hi77h7gb7Hd4OvORaUSSafFR6HDLZsK1IL848j3vT4tDSnd+CyDw0JQm1beE8uXJRZQxEUX2ue3OOIq3znRF0z1h8LCKBFmu3o6gFfZMsQ9fIg6MdalnqPCYMxN9Q/0xdfOcWW+957pJbmCMYfImdeVHmv0dKFQEBQSYLUA9Mu1Yyw/tgE3lYbm5RrRqUprqgVXKrBQicbLE100eGsU+LvQcxUIBI8+TjWIEk0ruG+++SavvvoqEydOJDIykoiICDZs2EBqaip+fn4Wx7ibVvbT0tJISUkBsAp7c3d3J83kcs+tj/xiMEjExyfn+3hbqFRK/Pw8iY9PQa83OLTvx53UWzfRJSSgcHNDGxRKWopxJTf1wQNiYpLke5/4wJgjJHl4EhNjGbaiCQxEGxXFg0vX8VKIUEtHURjve7norkpFfJqEIt34LPW+RkM28eYdq+f7OOJq3zn3Txule90rVc7x+SgDjSGssVdu4OZCz1Fv+k1JTNWjy2Vctu69Xmc0PAzp6UTdi0HppJDu9HvGz4/S3Z3YuBSr/dcf3jW202v58eoRfrx6hDI+pWgb1pw25ZqjVOTPuyOZcq/iHsZhKKTn6ufn6TIeUYFA4Do41SAySxMOHz6c554zVrutUaMGZ86cYcOGDXh4eJCebqk2YzZivLy88DCp39hq4+lpXHXLrY+CoNMVzgRCrzcUWt+PK4lnjB5DzypV0aNE4RcAgD4+nvSUNNw8jUayNt4oqqDw8rZ6BuqgYLRRUaTev49bxcpFN/jHBEe+79Pj4gFjkrpeLwHG8B9lkFEtMO3+PfEZy4SrfOckXzB6cd0rVclxPCqTsELaPdd6jgZTDpFBqbJ7XJnvvaRxB6USDAbS4xNQBzjHE52eZFzsU7h72LyOdJN4RPXAagS4+3Pi/mluJ95l27mdeKm9aRhSN1/nNUtv61JSXeq5CgSCRx+nLpOEhhrlU5944gmL7VWrVuXmzZuUKlWK+/ct1aDMr0NDQ+VQOVttzH3n1ofg8SDlgklQ4YknAVD6+MiJz7rYGLld1mKemZGFGEQtIpcnaw0iM26mWkT62FgM6ULa15WQ9HpSrxrDqLNTmDNjVppLv+9aaoEFLcyqUChQeTlfWEHKRVBBazBeZxmfUgys2Zd5LadTxb8SAAnp+VfIMxtEQlSh+KDT6Rg2bCDnzp3JvbGJ69evMW/ebHr16k6bNuH06tWD+fNnc+PGdYt2e/Z8TXh4Q4t/rVo1pVevHixfvkRe3L59+7ZVu8z/3nhjnNxnr149WLt2jWMuvpB4550ZVtfQtm0L+vfvy65dO+R2tu5P5n9bt262aLd9+2dW5zLfuxMnjlvtW716JeHhDfn88+zrTEVFRbFy5TJefLE3Tz3VgvbtWzNixBB27dqRrQpobv0mJCSwbNlinnuuJ61aNaVr1/a8+eYb/PffObnNgwcPePHF3iQ5UJHTqR6iWrVq4e3tzenTp2ncuLG8/fz585QvX54mTZqwa9cuEhMT8TFNbI4cOYK3tzfVq1fHzc2NSpUqcfToUVlYQafTcfz4cfr16weQax+CRx9Jkkg2K8xVMxrfCoUCdVAQ2nv3jEpzpY15ZuZJSNaJNGSuRSQMIlcnO8NW6eOD0tMTQ0oK2ocPcS9TxhnDE9jAoiBrlrzQrLiFmIuzuo5BJElSgVXmwKg0p09McKpBZEjNWXJbJ5nEI5TGKYSXxpMSnkFcirtCuj7/Cw1Kd2OIoCFdGETFha1bN1OxYmWqV69pV/ujR48wdepEmjYNZ+bMOYSGluLWrZts2bKJIUMG8N57i2jcuKnFMXv3fiv/rdVq+fvvv5gzZxbp6WlMnDhF3jd//kLq1rXOC3dzKzqlREdRp05d3n13kfw6NTWVPXu+5t135+Dn50f79h3lfZnvT2a8vS3z8D74YDktWrQkLKxcruc3GAzs37+XChUqsnPnV7z4Yj+rNpcvX+K118ZQunRpxo4dR9Wq1dBqtRw9eoRVq5Zx9uy/TJ36Vp77nTRpPDqdjunTZ1CmTFmio6P55JONjB49nPXrP6FSpcqULFmSjh07s3z5Eqtz5Beneog8PDx45ZVXWLVqFXv27OH69eusXr2aX3/9laFDh9KxY0dKlizJ+PHjOXfuHN999x2LFy9m2LBhct7QsGHD2LBhAzt37uTixYv873//IzU1leeffx7Arj4EjzbaBw/Qx8aCSoVH5QwpX3WgUZ0qs/R2dp4FAI0p3Er7UEhvuzoZz9HXYrtCoUBTwuglErWIXIvcCrJmxuwhMiQnyc/a6ej1sjJbQQwicy0igxNrERnMNYiyKcpq9hCZDSIAN5Xx9zTdoM33ec0GmCQ8RMWCxMQENm/eyIABg+xqn5CQwMyZ0+nUqQvvvruI+vUbUrp0GRo3bsqSJSsJD2/OjBnTSchSODs4uIT8r1Sp0nTq1IWuXbsRGbnfop2fn79FW/M/X1/L34HigFqtsbiGsmXDGDUqgnLlyltdt61rDg4ugYeHp1W7uXNn2VW/7ejR37l//x5jx/4fV69e4c8/T1jsNxgMzJgxjVKlSrFmzTratHmKMmXKUqFCRfr2fYnZs+eze/dOrly5nKd+L126yKlTfzJp0lQaNWpC6dJlqFWrNnPmzMfX14/du3fKbfv2fZkDB/ZZeRbzi9MzCyMiInjttddYsmQJ3bt358CBA6xYsYJmzZrh7u7OunXrMBgM9O3bl1mzZtGvXz8iIiLk4/v27cu4ceNYunQpffr04datW2zYsIGgIONk154+BI825nA5j0qVLZKUNab3iC7GhkHkba1wpDZ5iHSiFpHLY65BpPSxfo4as3fhwYMiHZMgZ3IryJoZpbs7Kv8AwHUMW3NRVsh/YVbIXJzVmR4iU8icu+2VdZ3JINIoMhtExmsuiIdI4W4OmUvNdx/FFXPtJ2f9y0+R4127dhASEkJl00LjO+/MYNgwS+Pozp3bNG/eiGPHjnLwYCTx8XGMGfOqVV8KhYJx4yYQHR3FwYORuZ5bpVKj0RRsUdscLnbwYCSDBr1MmzbhDBnSn6tXr7B+/Vq6detI585PsXDhfPn+rF27hpEjh7F+/Vq6dGlPx45tmD17Rp5Ct1JTU5g79x26d+9EmzbhDBr0MocPH7LrWJVKJeff55Xp02dw6tSfbN++Lde2e/Z8TZUqVWndug2hoaXYufMri/0nTx7nwoXzvPrq/6G28X0XHt6C7dt3UqmSZb51bv0qTYthv/32i8V7Uq3WsGbNOgYNGipv8/f3p3HjJnz22dbcL94OnBoyZ2bo0KEMHTrU5r4KFSqwfv36HI8fPnw4w4cPz3a/PX0IHl1SzhvrD3mZ8ofMqE0GkTazh8g8kbaVQ2SqZaXPsnolcD30icZnZCsXTPYQPXSNibTASG4FWbPiFhJCSlws6Q/u41HJ+SInZkEFyH8OEbhGcVZzyJwiu5A5s4dIlckgUpo8RPqCeIjMBtHjld8nSRJX584hxVQawhl4VqtGxf9Nz5N0+o8//kCLFq3k1z17PkNExAhu3rwhh2VFRu4nJCSUxo2bsGfP11SoUJGAbMRCQkNLUa5cef766xS9ez9vs41Wq+XYsSMcOLCXHj2eycMVZs+aNauYNm0Gvr6+TJkykZEjh9KiRStWr17LyZMnWLBgHuHhLWjdui0AZ88a1TCXLVtFUlIS8+a9w7RpU1i6dKVd5/vww9VcunSBxYuX4+fnx+7dO5g+fSpffLGLMtmEcSclJfHVV9u5evUKo0blb0G/QYNGvPDCS6xevZIWLVpRrlx5m+3i4uL4+ecfGTJkOAqFgg4dOvHFF58RGxsjP7uTJ0/g7u5OvXoNsj1f+fIV8txvpUqVad26LR9++AG7du2gadNm1KvXgKZNwylTpqzVOVq2bMPGjR8zadLUfN2TzLiEQSQQFCYp5vyhLOIdGSFzGTlBuhxC5pQm5UJ9cjKSJBW45oag8Mgx9NEF808ed3QJGQVZPSrZZxBpSoaQcuG8yzxHc1FWVKoCFW42v2cNzjSIcgmZkw0iWx4iQ0FyiIwG0WMZMlfMfk4MBgNnzvxL79595G0NGjSkbNkwIiP3M3z4SMBoEHXr1gOlUklcXAw+PjmHr/n7BxCTKWoDoF27lvLfqampuLm506lTZyIiXrNo9/rrr8kehszMm7eA5s1bWm0306/fQBo2bATAU0+14/PPtzFlyjQ8PDypWLESa9eu4fLlS7JBpFAomDv3PUqaRHomTnyTCRNe49q1q1SoUDHH6wO4desmXl5elC0bhq+vLyNHRtCgQSP8/DLuzenTf8rXLUkSqampBAYGMXbsONq165Dt/cnMvn3fyYrLZiIiXuW3335mzpyZrF69zuZx3367n/T0dDp27AJA585d+PTTT9iz52sGDBgMQHR0FH5+fhb3+8GDB/Tt28uir8GDhzFkyHC7+wV4991F7Nq1g8jI/ezbt5dvvtktG1BTp07HO9NCZ+XKVbh//x737t0lNNSy5mheEQaR4JFGFxtrDKlRKPCoUs1in2wQmb58Jb0eQ7JRbtaWZ0FllmnX65G0WhQiB81l0SeaxTGsf3w1wUIcw9Uwe4fcSpexGa5qC1czbM2CCsoC5A9BxneP3pk5RGZRhVxU5jRKaw+RtgAeIvN36uOmMqdQKKj4v+lyMWmnjMHNLU+LfHFxcej1OgJNv6NgvI7u3XvKBtF//53jypXLLFiwGICAgEDu3TuXXZcAxMfHERJiWZR58+Ztcv9ubu4EBwejUqmsjp069S1q1apttd1suGRHZpEBDw9Pq/wbd3d3i/It5cqVt+jTLORw6dJFuwyigQMHM3HiBLp27UCtWrVp1iyczp27WhiL1avXZNasOYAxjMzT00tOBcmK+f5kxcPGgoaHhyfTp89kzJgRbN++jTZt2lm1+eabr3nyyeqUL19eHku5cuXZtWsH/fsPQqFQ4O8fQHx8vMVxQUFBFmOJiBiJNpPn3J5+wRgW2KfPC/Tp8wJJSUmcOnWSQ4cOsn//XiRJYu7c9+Q+AwONnqWoqChhEAkEOWHOE9GUKIEqy0qJOYdIG2OU3dYlJclJ0bYmZQp3D1AoQJIwJCc7rWiiIHfMCem2PEQqU6FmfZYvc4HzSL1sElSwM1wOMqk+RruGYWvOISqIoAK4RsicVABRhbQCqcyZQuYeQ5U5hUIh51AVB5RK4+TVYLCsF9W9e0/WrfuQs2fPcPBgJHXr1pdDs+rXb8DBg5FERT0k2LQwlZmHDx9w/fo1nn22t8X27EK7slKyZIjdbTOjzhLimpthmLW9ubCyLe+ULerUqcfu3fs4duwof/xxlH379rB+/TqWLl1BkybNAKMRZu+15PWa69dvSN++L7F69SoqZfHIX7hwnvPnz6FQKGjZsom83WAwIEkSx44dpVmzcOrVa8CmTev555+/qV27DmA0ZDKPJbPRam+/hw8f4sqVKwwb9gpgVMpr2bI1LVu2JjAwkB07vrQYr/n9Z34/FgSniyoIBIWJXp4YW3sKzDlEhsREDGlpclFWpaenzRwAhUKB0tPoJTKkJBfWkAUOIKccIrWfv9xGMojij65AyiWjoIJn5dwFFcyoTaIK+vi4whhSnjGHzBVEUAEyq8y5gqhCziFzFh4iOWTOASpzqY+fQVTc8PcPQKPREBMTY7G9dOkyNGrUmO+//45Dhw7So8fT8r5OnboQGBjEqlUr5G2//fYLAwa8yOHDh1i1ajleXt50796jyK4jP9y4cZ3ExIxc4r//Pg3Ak0/aV8pl7drVnD59ijZt2vLGG5PZvn0nYWFhHD78faGM1xZjxrxGSEgICxfOs9j+zTe7UavVfPjhejZv3ib/++ij9Wg0GnbtMoogNGsWTuXKVVi1ajk6nfVnPj4+npSUlDz3e//+fTZsWMu9e3et+vTx8SUoKNhiW7QpB7xEiZy9gPYgPESCRxpzLoktkQSlpxcKdw+ktFS0MdFoMP7I25pEy8d4eRqlfpOFQeTKZOQQWXv6VL6+sqdPn5Agi2UInIOk15Nqkma1R2HOjNnTp3MRT58jahCBi6jMmT1E2arMGa/VwkOkNF631hEqc4+hh6g4UrNmLf7775yF0QPQo8fTLFz4HgaDno4dO8nbfXx8mT17PpMnT+DNNxN5+eX+lCtXntq16zB16iTAGPaWnehCbsTHxxEVZa0Cq1Aosw03yw/JycnMmvU2o0ePJSoqikWL3qNjx86ULm0UREhMTECr1cnhXFm5desWBw7sZ+rU6ZQtG8a///7D3bt3qFOnbr7GY+uawVh/KTvJcQ8PD6ZNm0FExAh5m1arJTJyP+3bd7RZz6lTp65ERu6XPXxz577H+PGv8sorQxgwYDDVq9eQRS+2bNmEVqulVq3aeeq3Z89n2LnzSyIiRjJixGjq1KlLcnIyp0//ySefbOSNN960OPa//85RqlQpYRAJBLmR4SGyEQKnUKAJCiL9zm200dHoNEaXq9JGmJUZlacXOsCQaeVD4FpIer38fGx5BhUqFSpvH2Pxy/h4YRA5mbRbN5HS0+0qyJoZs0FkSExE0ukKpOzmCBwWMuflSjlEnjb36wx6oDDqEJlV5oRBVBxo06Yd+/Z9Y7W9XbsOLFz4Hm3btrNIgAdo2LARGzduZcuWTcycOZ2oqCgCAgLp0qUbKpWKFSuWEBcXayGvbC9moyornp6eHD78a577y47Q0FI88cQTjB49HJVKRZcu3YiIGCfvX7x4ESdPHmfXrr02j580aQrLly9h5szpxMXFUbp0GSIixtGtW/48Yz16dLa5vWXLVrz//vJsj6tfvwF9+74sy1b//PNPxMXF8vzzL9ps//LL/dm37xt2797FsGGvUKlSZbZs+ZzPP/+UjRs/5vbt2xgMesqXr0DPns/Sp88LlChRku+/P5Snfj/8cD0bNqzj448/4v79eyiVSp544klmzJhN27aWOU8nTvxBq1Zt7blNuSIMIsEjTU5qYwDqwEDS79xGFxWN1tv4g55TUrdZac4gPEQui7yyrlDI+RhZUfn5oU9MQBcfhzu5V+0WFB6ppnA5ewqyZkbl7QNKJRgM6BMTUOdzVdlRmGW3C2qYuUTInMkgyS6nRWsyejTKDOPPITlEbo+xylwxpGfPZ/j44484e/YMNWrUlLd7eHjy/fc/Z3tcWFg5pkyZbnPf2bNnuHjxvNx/z565S2uXKVOGI0dO2jXmzEaKreNGjBjNiBGjsz0GjIupI0aMYcSIMTbPMW3a24wYkb1B5+3tw9Spb2W7/+23Z2W7LzP23p+c2o0f/wbjx78hv87pPlar9oTVfl9fX155ZRSvvDIq2+Pat++Qp379/f2txmWLqKiH/PHHUT755LMc29mLyCESPNLIyfXZhMFl1CKKQpeQs/EEoDQpzemFh8hlMecPKT29sp1gC2EF1yHtxg2APNcSUiiVxvBHQBfn/DwiR4fMGVJTkXS6Ao8rP2R4iLLLITJ7iDKSph0TMmdSmRMhc8UCf39/+vUbwLZtjimMCVCjRk2efrqXw/pzBlu2bKJdu/bOHsYjz/btn9GpUxe7lP3sQRhEgkea3D1EGcVZdQnZJ+KbUQlRBZcnt2cOGcIKOhdJyH+cMeer5PS5yw61Cxm25pC5gspuK728jDlu4LRcxdxV5mx5iBwoqiA8RMWGwYOHce3aFc6c+dfZQ3EZ+vUbyMCBQ5w9jEea+/fvc/jwIcaPn+iwPkXInOCRRp4cZzPZMktv62Ki0XoYf9Bz9BCJkDmXJyfJbTPCQ+Q6SOkmz4pb3g0JlZ8/cMMlDNsMlbmC/awqlEqUnl4YkpOM72XTe7UoyVCZy05UwYaHyJGy22lpovh1MUGj0bBp06fOHkaRYSukLiuaAi6KCHInJCSE7dt3OrRP4SES5Er8b79yZcokUq9fc/ZQ8ow5nyQ7oQS1ScLR6CFKzLEtiJC54oB9HiJhELkKhgKEmskS6i7wHB0VMgfOV5rLUJnLLmTOhofIVJjVIBnQmwymvCLnLEmSfD8FAoGgKBAGkSBXYg8fQvvwAclnzzh7KHnG7pC5KPtC5oSHyPXJzSsIZs+CCJlzBSSt0aOg1OS90LErSW870iByZnFWyWBASjc9Exshc5IkoZNsqcxlXHe6IX9eosweKRE2JxAIihJhEAlyxJCaSuq1qwDyj2RxQZKkXEUVNEFGZSpDSjKp9+8b2+YUauUlcohcHbn2lAiZKxYUxJDIeI7ON2xl2e0CFmaFTB6ixKKX3s4sea3wsA6ZMxdlBUuDSKVQoVQYpxTp+vx5dxRKpRxyKIQVBAJBUSIMIkGOpFy6CAYDUPxqQ0hpabJKU3ZGjtLDU/b6pN0zGUQ5eojMBpEImXNV9HbkEGWIKgiDyNnIBpFb3j1E8nN0AZW5goT+ZcX8HeQM6W2zwhxKpU3jTifZNogUCoWsNFeQPCKFqEUkEAicgDCIBDmScuE/+W+pmK3YmSfGCrU6x8mWOY/IjD11iJyl/iTIHXtyiGTPQkI8ksngFzgHgylkrmAeIucbtoUSMpdc9B6izApztkQNtJk9RAqVxT6zsIJWKM0JBIJihjCIBDmScv68/LehmIXMZQ6dykmtyJxHZCbHUCsRMufy2JNDZBZVwGBwagFMQSZDIh+hZi4lqqBzjMocOFdUQa5BlK2ggvE61Uq11feq2UOU7iClOYFAICgqhEEkyBaDVkvq5Uvy6+K2YmfPxBgypLeNjVXZ1t4AETJXHDDY4SFSqNUovYyTThE251zMstvK/Mhu+5sMoqREJH3+lM0chdmwK2gdIshUnNWpBpFtyW2zh0ijtDb8zB6i/OYQgQiZEwgEzkHUIRJkS9rVKxaV0oudh8iOXBIAdSaDSOWdszfJLLttSE1FMhhQKMWagqth93P38yM9OcmYkF+2bFEMTWADWYwgPyFzPj7GIqaShD4hAXVAgINHZz+Old02vned4iEyGSKKbBaGZA+Rwnr6oJGLsxbAQ2QKby5uC3CPKzqdjpEjhzJ58lSqV69p1zHXr19jy5bNHDv2O9HR0QQFBdOsWTgDBgymXLnycrs9e75mzpyZFseq1WpKlChJ+/YdGTUqAnd3d27fvk3v3j2zPV/Llq14//3lAPTq1YMePZ7OtZaQM3nnnRns2/eNxTZ3dw/CwsJ44YWX6NWrN2D7/mTmtdfG07//ILnd669Ppm/flyzamO/dqlUf0ahRY06cOM7YsSPZsWMPZcqUybGtmQsXzrN162ZOnDhOfHwcISGhdOjQiYEDB+Nt+i4zj+HIkZPZjrdXrx7cvXvH5j5PT08OH/4Vg8HAK68MYdKkKdSoYd/7zV6EQSTIluTzxvwhhVqNpNMVuxU7ezwFYBkyp86lrTmHCEnCkJqCyiv7fCNB0SMZDPIkMrfnrvLzg7t3hIfIyZgXWhT5kN1WKJWofH3Rx8eji49zrkHkwJA5Z8puyx6i3AwiGx4id6XZQ+SAkLlilrP6uLJ162YqVqxstzF09OgRpk6dSNOm4cycOYfQ0FLcunWTLVs2MWTIAN57bxGNGze1OGbv3m/lv7VaLX///Rdz5swiPT2NiROnyPvmz19I3br1rM7p5mbb2+nK1KlTl3ffXSS/Tk1NZc+er3n33Tn4+fnRvn1HeV/m+5MZ7yz50B98sJwWLVoSFlbOYeM8fPgQM2ZMo3Pnrsyfv4CgoGAuXDjPihVLOXr0d1at+ggv00KyPfTrN5D+/QdabVeYFCyVSiVjx45j9uwZbNr0qUOL4AqDSJAtKSaDyLPaEySfPVPsZLfliXEeQuZym0QrNRoUGg2SVoshRRhEroYhJUVWRVTm8txVcv6J8xXKHlckgwFMoW75DTVT+fmjj493+nMsjMKs5rIBRUlGUdb8hMyZc4hEyNzjQGJiAps3b2Tt2g12tU9ISGDmzOl06tSFqVPfkreXLl2GRo2aMH36FGbMmM5nn32Fr6+vvD84uIRFP6VKleb48WNERu63MIj8/Pyt2hZX1GqN1bWMGhXBd999S2TkfguDyN5rDg4uwdy5s/jgg7U5RsLYS1TUQ2bPnknv3s8zfvxEeXuZMmWpUqUqL77Yhy+++IzBg4fZ3aenp2eu19OoUWPc3Nw4cGAvTz/dK7/Dt0LE+whsIun1pFy8CIBX7TpAMQyZy4eHKLe2IIqzujLmZ65wd891gq12oaKejytmIwLyJ7sNmZ5jnHOfY0FC/7LiTFEFKdVoiOTHQ6Qx5xAJlbk8I0kS2nS90/5JkpTnMe/atYOQkBAqV64CGEO9hg0bZNHmzp3bNG/eiGPHjnLwYCTx8XGMGfOqVV8KhYJx4yYQHR3FwYORuZ5bpVKjyYdXOTO3b98mPLwhBw9GMmjQy7RpE86QIf25evUK69evpVu3jnTu/BQLF86X78/atWsYOXIY69evpUuX9nTs2IbZs2eQlIfFi9TUFObOfYfu3TvRpk04gwa9zOHDh+w6VqVS5dsrMn36DE6d+pPt27fl6/isHDiwn7S0VIYOfcVqX1hYOVat+tChBktmOnXqwqefbnFon8JDJLBJ2o3rSGmpKD098ahUGSh+P1CyylwOMtoA6sBA+W/7DCIv44q0EFZwOezNHwLXkmx+XLEwiPIZauYqz9FQALW8rJi9m4bk5CLPVczwENk2iMyS2hql9XU6RmXOzTSO4vV7UxAkSeKrTSe5c9N57+HSYf70GdwgT56DH3/8gRYtWsmve/Z8hoiIEdy8eUMOy4qM3E9ISCiNGzdhz56vqVChIgEBgTb7Cw0tRbly5fnrr1P07v28zTZarZZjx45w4MBeevR4Jg9XmD1r1qxi2rQZ+Pr6MmXKREaOHEqLFq1YvXotJ0+eYMGCeYSHt6B167YAnD37LwDLlq0iKSmJefPeYdq0KSxdutKu83344WouXbrA4sXL8fPzY/fuHUyfPpUvvthllbdjJikpia++2s7Vq1cYNSoiX9fZoEEjXnjhJVavXkmLFq0s8rXyw7lzZyhfvgL+/gE299ev36BA/edEy5atWbFiKTduXC/wdZgRBpHAJpnD5cwrhcXOQ2Tn5Fjp7o7Kxwd9YqJ9E2kvL7QID5ErYq+yIGSWbBYhc87CbESgUqFQqXJunA1qf9d4jg4NmcsUc29ITrbre8lR5J5DZAxxVCutn5e7quA5RAq3xzVkruAhTEWJwWDgzJl/6d27j7ytQYOGlC0bRmTkfoYPHwkYDaJu3XqgVCqJi4vBx8c3uy4B8PcPICYm2mJbu3Yt5b9TU1Nxc3OnU6fORES8ZtHu9ddfQ2lj8WDevAU0b97SaruZfv0G0rBhIwCeeqodn3++jSlTpuHh4UnFipVYu3YNly9fkg0ihULB3LnvUbJkSQAmTnyTCRNe49q1q1SoUDHH6wO4desmXl5elC0bhq+vLyNHRtCgQSP8/DLuzenTf8rXLUkSqampBAYGMXbsONq165Dt/cnMvn3f4WnOezYREfEqv/32M3PmzGT16nW5jjUn4uPj8PX1K1AfWdm0aT2ffvqJ1fa+fV+28CyWK1cejUbDP//8JQwiQeGSfMFYf8iz2pNyLHmxK8yah8mxJijIboNIDpkTtYhcDnuFNCDDsyBC5pyHOS+xIFLV5lwwZz9Hs6iCI2S3FWo1Sg8PDKmp6JPs+15yFLLKXLY5RNl7iDJU5goSMlc8f28KgkKhoM/gBui0zisSrdYo8+QdiouLQ6/XEZgp5FyhUNC9e0/ZIPrvv3NcuXKZBQsWAxAQEMi9e+dy7NeoUhZisW3z5m1y/25u7gQHB6OysYAydepb1KpV22q72XDJjswiAx4exhwWD48MQ8Ld3Z30TAvC5cqVt+jTLORw6dJFuwyigQMHM3HiBLp27UCtWrVp1iyczp27WhiL1avXZNasOYBRSMDT04ugoCCb/ZnvT1Y8bCxqeHh4Mn36TMaMGcH27dto06adxX61yVMvSdbvRfM2c5uAgEDu3j2b2+Xmieeee95KCQ/Az8/S8FKpVPj5+RMVFeWwcwuDSGCFZDCQYjaInngiY8WumHmIDHkIn3IrVZrU69fRBAfn2tYsva0XHiKXw968McgsqiAMImfhiLwbtYuEzGUUmHXMz6rS29tkEBVtHpEh1RgKnB8PkZuy4HWIHtfCrAqFAo1b/rykzkCpNBpPBoPlxLl7956sW/chZ8+e4eDBSOrWrS+v4Nev34CDByOJinpoM3H+4cMHXL9+jWef7W2x3V4PQMmSIfnyFqizfGZzMwyzttfrTUI+doa21qlTj92793Hs2FH++OMo+/btYf36dSxduoImTZoBRiPM3mvJ6zXXr9+Qvn1fYvXqVVSqVMVin9nwSEhIsDou3vQda25Tp049Dh6MJDY2xmYY5NKl7+Pt7Z0niXM/Pz+7r8dg0Mvqc45AiCoIrEi/cwdDYiIKNzc8KlSUY7rR6y3qErk6eZkch770MtX+71X8MmnrZ0eGh0jkELkaeckhUvubJtIJ8flKKBYUHKkAkttmMjxEj07IHGR4tou6OKvZEMneIDJep9pWDpGq4DlEClPu0uNmEBU3/P0D0Gg0xMTEWGw3KsY15vvvv+PQoYP06PG0vK9Tpy4EBgaxatUKedtvv/3CgAEvcvjwIVatWo6Xlzfdu/cosuvIDzduXCcxMcNg+Pvv0wA8+WR1u45fu3Y1p0+fok2btrzxxmS2b99JWFgYhw9/XyjjtcWYMa8REhLCwoXzLLaXK1ceLy9vTp/+0+qYU6dO4u3tQ/nyFQDo2LETXl5ebNz4sVXbq1evsHPnl1bGo6PQ6/XEx8fn6v3LC8JDJLBCzh+qUtUYupFpnyE9DVUhvcEdiaTXywaLvSFzgVXaEROTBLqcwxbM8f0iZM71yBDSsD9kTtLpjHkauYhvCByPwQFGRIaHyMkGkVyHyFEGkVlprmilt2WVuWxC5jJU5mx4iGSVuYKLKhQ3EZ/HkZo1a/Hff+csjB6AHj2eZuHC9zAY9HTs2Ene7uPjy+zZ85k8eQJvvpnIyy/3p1y58tSuXYepUycBxrC37EQXciM+Po6oqIdW2xUKZbbhZvkhOTmZWbPeZvTosURFRbFo0Xt07NiZ0qWNggiJiQlotToCA21fx61btzhwYD9Tp06nbNkw/v33H+7evUOdOnXzNR5b1wzG+kuZ5csz4+HhwbRpM4iIGGGxXa1W07//QD78cDVubm40adKM9PR0Tp48zrp1HzFkyDA5XDEgIJBJk6byzjtvk5SURK9effD39+fvv/9izZpVVKv2BC+/3N+i/99//9VqLFWqVJPDJFNSUrK9Hn//ANnAunDhPHq93maIZH5x/ZmtoMhJuWAyiJ54EjCFgKhUoNdjSEsvFrV35DAThSJXlbm8ovQUIXOuit60amdXLpjGDaWnJ4aUFPTxccIgcgJmr4rSrSA5RCaDKDERSa/PtzhDQXG0h8hZxVkNaaaQuWxV5sx1iGypzImQuceJNm3asW/fN1bb27XrwMKF79G2bTu8syxONWzYiI0bt7JlyyZmzpxOVFQUAQGBdOnSDZVKxYoVS4iLi2XQoKF5Ho/ZqMqKp6cnhw9bT8TzS2hoKZ544glGjx6OSqWiS5duRESMk/cvXryIkyePs2vXXpvHT5o0heXLlzBz5nTi4uIoXboMERHj6NYtf56xHj0629zesmUr3n9/ebbH1a/fgL59X+azz7ZabB8+fCSBgUHs2rWD5cuXoFAoKF++AhMmvEHPns9atO3SpRshISFs3foJkye/TmJiAqVKlaZnz2fo12+gRS4WwIQJlkIYANOnz6RnT6Ni4KeffmJTVAFgw4Yt1KhhLAB84sRxqlSpStmyYdleX14RBpHAAkmSSM6kMGdG6eaGISWl2CS6yp4CTy+HS9aKkDnXRS7Ga2cSusrPD0NKCrr4eNxK25Y7FRQejjAiVD6+oFCAJKFPTECdjQRsYeMIb1dmMoqzFnUOUf7rELk5QFTh8VWZK3707PkMH3/8EWfPnpEnqmBM3P/++5+zPS4srBxTpky3ue/s2TNcvHhe7t88Uc6JMmXKcOTISbvGnNlIsXXciBGjrXJesho2CoWCESPGMGLEGJvnmDbtbUaMyN6g8/b2sShMm5W3356V7b7M2Ht/cmo3fvwbjB//htX23r2fz1b6PCsNGjSiQYNGBR5rdgakLfbt+4a+fV+2u709iBwigQXaBw/Qx8aCSoVH5YxkO3PRRKmYCCvkRVAhr8ghc8JD5HKYJ4/2envUQljBqUgOqN2jUKmMRhHOfY6yQISDQorNob5FL6pglN1W5OohsmEQOaQO0eOnMldc8ff3p1+/AWzbtjX3xnZSo0bNQivmWVRs2bKJdu3aO3sYjyxHjx5Bq9XSo0dPh/YrDCKBBamXLgLgUbESykyV45XFbNUuQ1DB8WFQ5pA54SFyPfSmvC7zM8qNDOltUYvIGZiVKxVuBas472wJdclgAL1Rfc0RstuQOWSuaHOIMuoQ5ZZDZMtDVPA6RCJkrngxePAwrl27wpkz/zp7KC5Dv34DGThwiLOH8UhiMBhYs2Ylb789C7WD8jXNiJA5gQXmHAxNFklM84SluEhvy2pjdiTX5xUhu+26GJJN+Q95NIiEh8g5OEJ2G4yevvRbN50mrGD2dEHxDpkzpKVhSDaeL7vQQ61kh0FUkJA5oTJXrNBoNGza9Kmzh1Fk2Aqpy4rGQd8BAmuUSiUbNmwpnL4LpVdBsSW7KuVyGEMx+ZGSc4gKI2ROFGZ1SSRJkmuoqLw8c2ltRO0iks2PKxmFWR3kIYpzkkGUqRyB40Lmil5UQWsqcqj09JQXfrKi05tC5hTZh8xpC+QhygjPFnL4AoGgqBAGkcACuQZFFsnVYuchSix8D5HIIXItpLQ0MBUJFB6i4oGjlNmcXZxV9hApFEZFTgegdEIOkfbhAwDUwSWyLU6pM3uIVNmLKqQ5QGUOSSo2Oav5Qxh7AkHhY//nzOkG0b1793jyySet/u3YsQOAs2fPMmDAAOrXr0/79u3ZvHmzxfEGg4Hly5fTunVr6tevz4gRI7hx44ZFm9z6EGQgJ9QWdw9RIYoqmFXmJJ1OVpYSOB85hFGlsjsnxdkT6ccdWZmtALLb4PzirJkNu9yq3NuLM0LmdKb6H5oSJbJtk6OoggPqEJlV5sBY9+5RQ6PRoFBAWjH5LRUIijNpaWkoFPaFMTo9h+jcuXO4u7vz3XffWfyQ+Pr6EhMTw9ChQ2nfvj2zZs3i1KlTzJo1C29vb/r06QPABx98wKeffsq7775LqVKlWLhwIa+88grffPMNbm5udvUhyMAccmQVMlfMPESGRLPaWCEYRJl09Q0pKQ5LohYUDLPIhdLT0+5JqbMn0o87ch2iAibHqv2dqxaYoTDnuO+CzIVZJYPB4eUDbKF9mLtBJIsq2AyZM/1OSAb0Bj0qG8Vbc0OhVKLQaJC0WuMCnO26ksUWlUpFQEAAMTGxALi7uwOOMaIFAoEZibS0NBISYgkMDJCLyeaE0w2i8+fPU7FiRblKbWY2bdqERqPhnXfeQa1WU6VKFa5du8ZHH31Enz59SE9PZ/369UycOJGnnnoKgCVLltC6dWu+/fZbevbsyfbt23PsQ2CJHDKXxSAyr9oVFynUwvQQKZRKuaCnITkZTF4GgXMx53SZc7zsIXPInCRJDlvdF9iH7Fkp5ipzjq5BBBkqc0gShtRUWe6/MDGHzGlKlMy+TY4eoozrTzek46m0/7OYGaW7B3qtFkNa8ViAyyulS5cGIDY2loQEJw9GIHhEUSggMDBA/rzlhtMNov/++48qVarY3Hf8+HGaNm2KOlOSanh4OB9++CEPHz7k9u3bJCUl0bx5c3m/n58fNWvW5I8//qBnz5659lEih5Ww3FCrHbtip1IpLf53CmnGkDmNl6fF9anMEqzadIdfd2FgMOUQafx97RpvXu+92SBSpKcWi/vhyjjsfZ9ufO+qvLztfibKoEDAODFX6tLzZEw9Cjj9O8fkWVG5uxXoc+QeGAAYDVtnfB6Vkil3zU1j9/lzvfdqDxRubkjp6ShSk1H7OX5xJyu6aKOogkdIyWyvQ2/KIXLTWD8zlaRBqVAaPUTo8v0slO7u6BMTUOiKx+9NXlEoFJQpU4bQ0FC0IuxaICgUNBqNXZ4hM043iM6fP09gYCD9+/fnypUrVKhQgTFjxtCmTRvu3r3LE088YdHe7Em6c+cOd+/eBbCy/kJCQuR9ufWRX4NIqVQQGOj4GjcAfn7Om5RdN01QfIMDLK4vzt+HGMBNKRXadTsSs3RsYOmS+ORhvPbeezdfH3TR0XipDAQUg/tRHCjo+16nMNaBcffzycN71BulhweG1FS8ScczMP8LJMUZZ33nPFAYE169/bwL9L2SLpXmMsayAQF+HigcJGxgL0oP4/nU7m55vo6c7r3G15f0qCi8lHp8i+B7RmcKmQuuXB7vbM4nKYzGX2A2nzN3tRsp2lQ8fdQE+uZvzGovD7RR4O2meKS/X1UqVZ4mbAKBoPBwqkGk0+m4fPkyVatWZcqUKfj4+LB3715GjhzJhg0bSE1NxS1LKIW7Kbk/LS2NFFPOgK02cSb51dz6yC8Gg0R8vGNVxlQqJX5+nsTHp6DXGxzat71oE43XlKKHmJiMZN50ybhKlxKXaLHdFZEkCa0pDiHZoEJrx3jzeu8lU62MuPvRSC5+P1wdR73v4x/EAmDQuOfpPary9cOQmkr0jbt4efrn+/zFEWd/56Savm9SdRToe0UyqIzxEQYDD2/ck3OKiorEaGOonqRU2X0d9tx7hZcXREURe/chuhL2hX3kF31KCjrT92aKmzfp2VxHqtYYxpaarLN5rRqFhhRSeRATh7suf8aMpDb+Zsc/jHP496ufn6dzozAEAoFL4lSDSK1Wc/ToUVQqFR6mnJXatWtz4cIFPv74Yzw8PEjPksRvNmK8vLzkY9LT0+W/zW08TaEvufVREHS6wplA6PWGQus713ObRBUktZvFGCRTsrAuLc1pY7MXfUqKXDVe8vDK03jtvfdmYQVtQpLL34/iQkHf9zqTGpfCwyNP/aj8/NA+uE9aTCxuj+mzdNZ3jlmkRVKpCnh+BSpvH/SJCaRFx4J30Wbi69JMYU9qTZ6vI6d7r/QyGhTp8QmF/nzS7j+Qzym5Zf8Z0poktZWS7WdmrkWUkp7/3wpzTpk2JUV8vwoEgiLB6csk3t7eFsYMQLVq1bh37x6lSpXi/v37FvvMr0NDQ+VQOVttQkNDAXLtQ2CJIdW2qILSrfjIbpvzhxQajVU9JUdhrnOjF8VZXQZZZS6PCx2iFpHzkLTGfJSCiipAZmGFolcMlMUhHFSU1UxRSm9rH5gFFXIOG9UZjItN6mwU5MzS22kFKM7qXq48KBRogh/PEFaBQFD0ONUgunDhAg0bNuTo0aMW2//55x+qVq1KkyZNOHHiBHrTaj/AkSNHqFSpEsHBwVSvXh0fHx+L4+Pj4zlz5gxNmjQByLUPQQaSJGFIM9chsoxrL06FWQtTYc6MXJxVGEQug7kOkb1FWc2onaxQ9jhjMIVfOUKu2l7pbUmSiD6wj4RjR3NslxccVWA2K0pZersIDCI7ahABaA3Ga9UobV+r2SAyt8sPJfu+ROVFS/GsUjXffQgEAkFecKpBVKVKFSpXrsw777zD8ePHuXTpEvPnz+fUqVOMGTOGPn36kJiYyLRp07h48SI7duxg48aNjBo1CjDmDg0YMIBFixZx6NAhzp07x4QJEyhVqhSdO3cGyLUPQQaSTieHmmX1rCjdjT9yxaFyuN7kIVIWQg0iM2Y1MkNySqGdQ5A38iO7DRm1iPSiFlGRI9chKkIPUfK/f/Pwy+3c3bQeSbK/inlOGHSFYxCZ66gViUEk1yDKXnIb7PAQmQyl9AJ4iBRKZZHngQkEgscbp+YQKZVK1qxZw/vvv8/48eOJj4+nZs2abNiwQVaGW7duHXPnzuW5556jZMmSTJ48meeee07uY9y4ceh0OqZPn05qaipNmjTh448/lqvSBgcH59qHwIiUmir/nV0dIkMxCJkrEg+Rp9lDJAwiVyFzYda8oJZD5kRBkKJGMnuIHGBIZBi2OXuIYr8/ZDx3WhqGpCSHfE9khMw52iAyhcyZFnkKE7PCnDrXkLncPERmg0jISQsEguKD02W3S5Qowfz587PdX7duXT7//PNs96tUKiZNmsSkSZPy3YfAiBwu5+ZmVRXdvIJbnDxE5slEYWAOmRM5RK6DHDKXzxyirJ6FuJ9/JPHUn5QeOabQctEedxwZaqa2w0OUfv8+SX//Jb/WxcU61CBSOthDpA401slKv3/Pof3aQg6ZyyFvxyAZ0ElmD5Ht6YOcQ2Rw/d8KgUAgMON0UQWB62AweYiU7h5W+8wTwmLhIUosfA9RRsicMIhchQwPUV5ziKw9C2m3b3Fvy2aSTp8i+ewZxw1SYIEh3XEGkT3iGHGHD0GmMDldbGyBzwumcGMcHzLnUakyAGnXrsrnKCy0D82iCtmHzOkNGbm42RpESlMOkfAQCQSCYoQwiAQyskHkYW0QmUPmioOHyGAOmSvEHCIhquB65D+HyFJUQZIk7n+6Rc6nM3tOBY7HkZ4VdS65YIa0NOJ+/dl4PtN7RBcbk6dzpN+9a9NALiyVOU1IKEpvbySdjrSbNxzad2b0yUny4o4mB7EhrSHDKNNk6yEqeA6RQCAQFDXCIBLImL0/Sg/r8CCzqIIhvTh4iIwJyIWbQ2ScUOlFDpHLkH/ZbeNEWkpLxZCWRuLxP0g5dzaj31TXf88XVySzGIFDRRVse4jij/yOITkZTcmS+DRoaGybRw/R7Q9WcPP9BaQ/sCzlUFgqcwqFAo9KVQBIuXzJoX1nxiyooPL1tbkgZkYnZRhEKoVtUQWNySASIXMCgaA4IQwigYzBVJRV6WG9wp7ZQyQZXLtQnllUoVBV5sweIhEy5xJIBkO+Q+aUHh7yRFb78AEPtn9m3KEyTvgk4SEqFCRJkj3ODpXdTkiw+o6SJInY778DIKBdB9SBQUDeDSJdTDQA2iy17aRCUpkD8KxiNIhSLxWeQaQz5Q+pc6n7o9UbDSKNUo1CobDZxl2EzAkEgmKIMIgEMuaVcIWNBPLMsrjm1VBXpShyiDKrzLm6gfg4YDbmIe8qcwqFQvYu3N+2FV1MNJoSJfFrGm7suxjkzRVHMufEOMRD5ONr/MNgkBdFzKRcOE/6rZso3Nzwa9kadUAAAPo8GESSJMlhxfoESy+UoZBC5iAjjyj1ymWH923Gbsltk4cou/whyBBVECpzAoGgOCEMIoGMOVfCdg5RxoTF1cPmikZ22zTpliQxYXYBzN4hhVqdr3wUc/6JOVSu5Ev9UPkaJ9iGVOEhKgzMktvgmBwihVqN0vSZ18dZ5hHFHjoIgF94C1Te3rJBpIuzP4dI0mplQYaswg2FFTIHGQaR9v499AmFIw2fYRDlJrmdu0FkDplLFyFzAoGgGCEMIoGMlIPKnEKplH/sXV1YwZBY+KIKCjc3OaTKVYUVtA8fPDbeK3OB3LzmD5kxe4gAvOvWw6d+A9lTKgzewkH2NCsU8mepoKht5BFpo6NJ/PMkAAHtOwCg8jfKWeclZC6zYZw1T6mwVObAWD5AU6oUACmF5CWyR3IbMhlEihw8REqzh8i1fycEAoEgM8IgEsjkpDIHFIsJoqTTyddRmB4ihUKBKpvirAnHjnJjwXy00VGFdv6ckCSJB59v48qUSUTv/cYpYyhqzPWg8po/ZMZsECnUakq+1N/Yl+lzkDkcT+A4pEyS29nlo+QVs0BG4onjxP74AzHff8eDz7aCwYDnE0/iHlYOIJOHKM7uRYPMaoNZlexktTwHF2Y141nZlEdUSMIK2gcmye2SueQQmQwijSp7g8hdFGYVCATFEGEQCWRyM4iKQ3FWOXdAoci3t8BelNkIK0RH7ifl/H8k/fN3oZ4/O2L27yXmYCQAcT/9+Fh4iczPIK/5Q2Y8q1QFIPiZXriFhBj7MhtELrwAUJwxFEKYmdo/AIC4Hw9z/5ONPPh0C4knTwAZ3iEweZIUCtDr5ZzD3JAyqQ3q4i1D1wrTQwTISnOFkUckSZIsquAQD5E5h8ggDCKBQFB8cHwGqKDYIstu2xBVAFC6ub6HyCy5rfTyQqEsXHs/Q3o7wyAyaLVyvRBnKNDF/fQjD3d8aXyhUqGLiSb10kU8qz1R5GMpSsxeOlU+PUR+LVvjXaeuPKGGjM+BJGS3CwWzMpvSAYIKZgI7dcaQkoxkkFCoVSjUahQqNW6lSuHTsLHcTqFWo/L1RR8fjy42Rg61ywl7PEQKTeH8pHpUyfAQSQaDQ7/bDElJ8mJYripzJiNHo8ze8DPvEyFzAoGgOCEMIoFMhux2NiFzxchDVJjhcmZsSW+n37qVUdCziGsUJf55gnufbAQgqHtPdLExxP/2K/HHjj4GBpHJQ+SVPw+RQqGwMIYgI5euqAqzGtLTefjldrTRUUg6nfGfVovSzY2SL/fHvUzZIhlHUeFIyW0zHhUrUXbcBLvaqgMCTQZRLJSvkGv7zAtBWVXmMgqzFo6HyL1sGAo3NwwpKWjv3cWtdBmH9S3XIPL3z9U41RmM321qZfY5Xxkqc677OyEQCARZESFzAhnzD77ChqgCZKyYu7aHqPAFFcyYPUSZDZ/Ua1fkv4tSbCH5v3Pc+XA1SBJ+rdoQ/FwffJs2AyDx+B9IJiPtUUWfXLAcIlsUdchcwrGjxH7/HUmn/iT5n79JOXeW1EsXST57hoQjvxfJGIoS2YhwoIcoL8h5RLH2Kc1lziXTxccjmRTnoHDrEAEoVCo8KlQEHF+gVRtlyh/KxTsE9nmI3EXInEAgKIYIg0ggk6uoQjHwEBmKoAaRGfPkW5/JQ5R6NcMg0heRh0gXG8vtlcuQdDq8GzQkdOBgFAoFXtVrovTxQZ8QT7JJTvpRJSNkLn8eIltkiIgUjYco+dwZAHwaNiJ06HBKjRiNT4NGxjG4uNR9fjCYZLcLy4jIDXWAUWnO3lpEhsyhk3q9hWe4MPKhsuIhCys4No/I3hpEkFl2O3sPUUbInDCIBAJB8UEYRAKZ3EUVTBNEF56cySFzReEh8rJWmUu7dk3+u6hC5hJOHseQkoJbWDlKjxyNwiRhrFCr8W3UxNjmj6NFMhZnYb7XjhTSMIfMFUUOkSRJstEa0L4j/i1b49csHPfy5Y370x+9yaWszOY0gygAsF96W8piGGfOIyrskDkAj8qmAq2O9hDZWYMIMhtE2V+nm6hDJBAIiiHCIBLISDkUZgVQuBs9RMUhZE5ZFDlE5pA500qxQZtO2q2b8v6iElVI+us0AH7hzVFqLMOP5LC5kyfkVexHkcIJmTMtABSB7Lb23l30sbEo1Go5gR4yPA4G7aM3ucwsu+0MVHkNmcvyvafLVCTVrDJXmMadR2WjEmLazRsO/Q7WPTSGzKntMIhk2e0cCrOa6xAZJINsQAkEAoGrIwwigYy9HiJXDpnL8BB5F/q5MjxExsl42o2bsqCCcXvhT6QNqamkmDwL3nXrW+33rPYEqoAADMnJJP/7T6GPx1nIogoODJmTPUQmgYPCJPms8Rl6VK1mYdQWhzDV/CIVQZhZTuTVQ5Q1dNKmh6iQVOYANIGBqAMDQZJIvXbVYf3aW5QVMnuIcqpDlPH+FWFzAoGguCAMIoFMbrLbxaEwq75Ic4jMsttGwyfNNEmxFUpXWCSfPYOk06EpWRK30qWt9iuUSnwbNwWMSfuPKnIOUT5V5myReWGgsMNEzflDXtVrWI7BZCxIj6B3zyALEThLVMGYQ6SLi7WrvXnByIwuPkNpLj/G3XfXfmLlkY0YJPvrhMl5RJccEzYnSVKecojs8RCplCqUCuPUQoTNCQSC4oIwiAQASHq9vAqt9LA9qSwOhVkNScY6RM6Q3TYrzHk+WR2wrE9UWCT+dQoA7zr1UCgUNtv4Ng03tj110qWN2YIg5xA5MGROoVaDKR/LUIh5RJLBQMp//wHWBpHZQ2Rw4c9cfpG/b5zlITLJrOvj4+1SYcz6HtCbDCJJkjIKs+Yhh2jvpYP8dO0odxLv2X2MRyVTHtEVxxhE+oQE43NQKFAHBeXa3h4PEWSEzQkPkUAgKC4Ig0gAWIaDKLLzEMmTM9edVBet7LalJyj16lUAvGrUlLdnluZ1NJLBQNJffwHgXa9+tu08KlVCU6IkUnq6nG/0qCHnEDlQVAEyhc0VotJc+q1b6BMTULi741GxksU+s/fkUfQQZchuOymHyNcXlEqQJAtvT3bIOZamcFyzQYReD6bPub0hczqDjmSd8XtDm4c8G7OHyFHS22bvkDogwC7D1G6DSCWKswoEguKFMIgEQKbVT5Uq2x9GcyidK3uInBIyl5yMIT2d9Nu3APCqbjSIMBgK9V6lXb+OPi4Whbs7nk88mW07hUIhiys8qmFzhZFDBJmEFQrRs2YOl/Os9oTRK5X5/CZjwZU/c/nF2TlECqUyw0tkh7CC+T2gKRkCgO7/2zvzODmqqv0/VdX7zPRsySzZQ8JkD1mBkIUQFkE2QxRfNChoEBRFUQT9gb5gABeQCCgKAgKvIFsAQXYQZBFCwpIASQiBELJNZp/pvbuq7u+PqlvdPdMz03tXd5/v5wNJuqurb9+qrr5PnXOeo9cQxZqVJPtZvBGf8XeFJd8jzDF+AiCKUHp6EOnqSvp1g8ENFZJJlwOACEtWEFEvIoIgigsSRASA4Q0VgJgIkYnTroyFcZYjBYmINVUI7fkcUFVIVW6tlkdPX8tlc1YfT5ebPnPYu7tVCzVB5Ht/c1zfpFKAybIhGKQspswB0QhR//qRbMLttvunywHRCFEpusypebCqHo5UjBX4OWBr0ASRorvM8aasQPKfxRuOCqJUnNhEux32MWMBZMd+mxsqWOrrk9peVoavIQIAm0gRIoIgigsSRASAmHQQ++CCyOwRolg3sMHqoLIJX3yzcNgocnZMmABBEGKiR7kzVvDq6W8Vhx027La2MWNga2oGk+WSa9IaK1ayHSHKtZEIUxQEdvD6oekD35+nzJViHyJeQ2QrjKkCEGu93TPstvw84xEi7jIX7UFkGbSOrz9xESI1+QgRANiaRwEA5K7OlF6XiFQMFQBATjFCFKEIEUEQRQIJIgJAchEi0eQF3nEL4yE+R7aIXXzztCe7XgPCn8tVhEju7UHoM83EoWLW7GG3FwQBFn3Rk6/+SPmCR7wEu91oSpst+HmUqwhRcPduqIEARJfLaMIa9/48Za4EI0SFTpkDYiJEvamkzGnfI153lM7niBVEcgopcwAgVWg3YhS/b5gth0fu1tLukjFUAJJzmQOiEaIQRYgIgigSSBARAGIstx2JDRUAQLCZ23abN9AUrNasL4wTIUiSEUHgd/kd4ycAGGi4kG1872tmCvYJE406iOEo1cV1ruqHgGhUtH8PmmwR+EiL1jmnTIUgDrwcGylzpRghKrDtNhB1mksqQhSKjxCxUAhqKJSWw1x8ylxqgkh06aYOvsxvbBh29Un2bTNMFYQka4jIZY4giCKBBBEBIComRPvgi0qzN2aNRrlyny7HMay39fd2TJigPW5EiHIkiDZr6XKVQ7jL9Se6uDbn8UuXaA+i7NeN8QgRy5HttlE/NGVg/RAQ05i1xEQsED0PCxsh0nsRJSGImH4jyFJdY4xZ6etLqymrN+I1/q6kUEMEAJIuiNQsRIh4dJXvcziSjhBxlznqQ0QQRJFAgogAEF3QC0NFiOzmNlVIJu0v28RGJaTqGmOBJeZQEKmRCHxbPwAAVMwevn6IIxgRotK6a2tYbmfZUAGIMVXIQYSIyTICH+8AALimJRZEhlmGqhqRiFKBn4digWy3geRNFRhjcdcXye3WXtfXm1bKnCeDlDlu5pKVCFGK351U+xBFKEJEEESRQIKIABCbMjdUDRGPEJlVEOlRrrwKouhCgkeHYh/PRXPWwI6PwEIhSNU1sI8bn/TrRKNAv7Tu2uYnZS7753zg00/AwmFIVVWwjRqdcBshxnBALTEha6YaImU4QRQOG72GRIcdFne19jqPJ+OUuVRNFXgNUTYjRMm6csq6SUKyfYiohoggiGKBBBEBIEXbbZMuqI3PkIOF8WDEC6JoU03RlbsIkW/zewCAitmzk3a1AmKOX4ktrI2UuRwcd8GRuwhRIMZue7DjGCsWSk3IMlPYbmsRXcXrGfJ7ESuIBZtda+oKLULELdFTEXa+NPsQATE1RBkKIqYohrtosummkaQbs/I+RKV1zhIEUbqQICIAACyYvO02FMWU6TuFSJmTXNFFuH18NFoj5dBUwfe+Xj80e05Kr+MLtlJbWPM5zkXvKcNqPgc1RLx+yJnAbpsjCEL0uJVYHZFRQ1RA222xosJohstttBPBBbFgs0EQRUg8QtTXBxbRrf7TTZlLNULEa4gyTJmLvTYlexNJNmqIhv6s3GWOUuYIgigWSBARAKI/+MlEiABzRomMhXGhUuZ0hznt8dzYbjNFQaRd6y7vmDQ5pdeKJVqgX4w1RGokYjTWdE2dOuS2peo0x13mUhES2UYQhKR6EXFBzM8Hi15DpPT1Rt3yUkqZi5oqpNKYFQDEGNttpqfxpUPUrt6RtCtn8qYK5DJHEERxQYKIAACoxg/+EKYKFgugWwObsY6oEC5zXPhYauvi7K+NxqxZjhDF3tVN1VWtVBfWOa0h0k1Gst2HSPF6tSirKMLa0DjktkKJ2qVHa4gKFyECYpzmugfvRdT/hlHUVMGTssucylT4ItEbJammzBmOcIqSUbRXNRzmkr+OJGuqYOU1RJQyRxBEkUCCiACQnCGBIAjR5qwh8/3QFSRlrrISAGCPMVQActeHiO9PsNmMVJ9kKdWFdS5ttwUjQpTdGwBqTDH7cHVghhlGidV+sXDhTRWA5Jzm+vdpk2IjRHrKXLKfwx8JgCEa2Uk1ZU6w2wE9oqNk0GTZuJGQA0FkN1zmSutaQxBE6ZLaioooWdQkaogAPW0uGDRphCj/KXNVhx+J8P79qFlxXNzjRspcBguWRChpLGKMMRkuc6W1sFb9+nHPSYRIF0RZjhDxxWgyRhDRXkQldtx4ZKWAtttArCAaIkLEmz4bKXOxNUQ8ZS65n1NvJN4MIdUIkSAIkFwuKB6P5jRXW5vS64331U0Z0okQJd2HiFLmCIIoEkgQEQCid0CFYcSEaLdDgUlriAoQIbLW1aHpW2sGPJ4rU4V00lw4fOGplliEyBCJOakh0k0VshwhSqXuiUcezPidywQeqSxkDREAWKr1lLnenkG36Z9SLFXpKXOevmgNUZKfo78gSrWGCNBuiCgeDxRf+k5z0R5Eyd1IUJlq9ExK3mWOBBFBEMWBqVLmdu3ahblz5+KRRx4xHtu2bRtWr16NOXPmYMWKFbjnnnviXqOqKm666SYsXboUc+bMwXnnnYc9e/bEbTPcPswCYwzBtraMCmXTJVkxIdhy15clUwpRQzQYubLdVjNY/AvUhyhlxBzZbqfijFeKZhhMUQBVBVBY220guV5ErF8NETdVUH2+aFPrZAVRjKECkHrKHBDjNJdBBDrVHkSx/ZKGrSESeYSodM5ZgiBKm6QjRPv370/7TUaNGjXsNpFIBJdccgn8MRf47u5unHvuuVixYgWuuuoqvPfee7jqqqtQUVGBVatWAQBuueUW3HffffjNb36DpqYmXHfddVizZg2eeOIJ2Gy2pPZhFjqf/Be2PfwQxlz4A7jmzs/reyfjMgcAot28i+pCuMwNRtRUwQ/GWEr9goYiE0c1sVRTr/y5qyHKVWNWI9KXQoSolFIdY8VdIW23gRRriPSUObGiQjOYUVVEujoBJC/sPBmmzAFREZNRhCiQWrQ5EhPJGi5lzm64zJnvd4IgCCIRSQuiFStWpLWoEwQBW7duHXa7m2++GZV6gTrnwQcfhNVqxa9+9StYLBZMmjQJu3fvxm233YZVq1YhHA7jzjvvxCWXXILly5cDANatW4elS5fiueeewymnnDLsPsyE7OkDAPg/2Zl3QZRMHyIgJkJkyhoi/U6tKQSRvshQFLBIJGuLvoxS5qylmTKXSdRsOPj3gYXDYKoKQcxOUD2VqFa0oW7pHLfYJqipmoNkm6RqiIwbRtr1TxBFSFVVUHp7IXd1ac8lHSHKPGVOquARoiykzCV5LZFZdJySMLRNN6XMEQRRbKT0S3TBBRdg3LhxSW+/e/du3HrrrcNut3HjRjzwwAN47LHHDGEDAJs2bcLhhx8OS8wP5pFHHolbb70VHR0d2L9/P3w+HxYtWmQ873a7MX36dGzcuBGnnHLKsPsYMWJE0p+nPxZLdjMO7fXaWJTurqzveygYY8YdUFuFc8j3lvQ75kIkktcxJgNPa7FVulIemySJcX9milThBAQBYAxiOAiLK0siTf+MlorUP6PVyRf35jp2mcy9Gg4bTYJtVRWQsvy5xIqoYBGVCCRbdtLymF6kb6msGPZYSHpUVpCzf9yyfd4nC9PTrwSLFVZbYQWRMKIegBZhFpVI4tYD+vVRckavjxZ3tS6ItAiRZLcldXz8iiZiLKIFsipDZWrKx9VSqQkiFgykfU4wPaJurahMah8soh0zq2iB1Tq0IHLqN87CSthU1xqCIIjBSOmX6JhjjsHs2bOT3n7z5s34y1/+MuQ2fX19uPTSS3HFFVegubk57rnW1la0tLTEPdbQ0AAAOHDgAFpbWwFgwOsaGhqM54bbR7qCSBQF1NZWpPXawVDGNuMAALWnJ+v7HvJ9g0FAr1uqa66HNESE5WClC14ADgvyOsZk4IXvNQ11qEhzbG539upQJJcTis+PCivgytJcdeuuTa666pTnP+DXnLEgR0x37ID05j7co9+BFgTUN9dnLYLDYcxlpEZV2QXYszRvXfqd84okjmNHpQt9AByW7F9zONk875Mh4O8FAIh2a8HPRVbjguhwQA0G4WIhOGvrBmzToae1VdRUGeN11tcitOdzo3+Rq8qV1GcJQ7tO1Tmr0ebrhCClfi3tq6tBNwCrHE57/g7I2jiqRtYktY+ARat9skrDHzPm0M7vsBpBTc3w1vIEQRCFJmlB9Nxzzw0QHsMxbdo0PPfcc0Nuc+WVV2Lu3Lk49dRTBzwXDAZh65dqZNfv3oVCIQT0O1yJtunt7U1qH+miqgx9fdm1VJadVQCAYHs7urvTT4VI+X157rwgoNcvQwgM/t6ynirh6+7L6xiTQdZTQLxhhnCKY5MkEW63E319ASiKmpXxiA5NEPUc7ESooiYr+/R3a+d1RLSmPP+RgBZJUUIhUx27TOY+1NoBQJvrnt7sGlhwRIcDqt+P7oPdsIvZifT5u7X02LBgGfZYRJgm8ny93qwft1yc98kQ7NTOY8GS+nmcCyzV1QgHg+jcvR8VDveA54N9mhgIMdEYL3PqURpFE0tBmSX1WTp92mevtrnR5utEMJz69zGsp6T5u3vTnr9gr0f7kw1/DgJAp57SbUninA3qvZlUpqKjq29YE4Z84nY78x4RJQjC/CR9leqfKtfV1YXNmzejr68voSval770JdhstiFT7B577DFs2rQJTzzxRMLnHQ4Hwv2K97mIcblccOiRjHA4bPydb+PUc/OH20cmyHJ2FxCi3jE90t2NSCgCQRo6LSFbhH26GYHdDkVhAIZwudOdyuRgKOufPxOYqhpGD8xqT3tsiqJm7XMJuttd2OODNUv7VHy6CLc7Uh6nyhclioJIWM56NCVT0pn7cJ+2MBOdzpydj6JdE0QRXwBSlt5DNo5jEuPW032VUO6+c9k875MhEtBvRlmtpriOSNU1wMGDCHV2wZ5gPArvQ2WLXlvEqnjhxCRLUp/FE9LEVbVdi9jKqpLyHAh27doie73pX+v4OehI7rsT1GvYJEEadnuRRZcW/lAILqu5rjUEQRD9Seu2zSuvvIIf/vCHCAaDCcWQIAj40pe+NOx+1q9fj87Ozri6IQD43//9Xzz11FNoampCW1tb3HP8342NjZD12oG2trY44dXW1oYpU6YAwLD7MBMWtxuCxQImy5B7e2Ctq8/L+/KC4WTMCAynMpPZbvPGiYA5TBWAqPFBNq23M2nMGmvswMJh08xTJuTScpsTdZrLnvW2msJx5Hbpakm5zGmfhTcLLjQW/WbUYNbbiRpXS+54QZRqY9Yau97LKA3bbbFCd5nLwHZbTdGxko/TKg3/OSVRgiiIUJmKsBqGC4VvhUAQBDEUaQmi3//+9xg/fjwuu+wyjBkzBmKad5qvv/56BPt1gD/hhBNw0UUX4bTTTsM///lP3H///VAUBZIeLXnzzTcxceJE1NfXo6qqCpWVldiwYYMhiPr6+rB161asXr0aALBw4cIh92EmBFGEra4OobY2yJ1d+RNESTrMadtwlzlzOV7xzwBJKnijRw5fpPPFbzbIhsscoDmWmcGePFO42MyF5TZHyEEvIsPyOAkhV5J9iPTPkmzvnlwznPW24WAZY7gg9YsQJfNZGGNGH6KoIErDZc6Vuctcqn2IInrdG+8xNBw20YagEiTrbYIgioK0BNGuXbtw8803x7m7pcNgEZr6+no0NjZi1apVuP3223H55ZdjzZo12LJlC+666y5cddVVALTaodWrV+P6669HXV0dRo8ejeuuuw5NTU044YQTAGDYfZgN+4h6hNraEOnuhBOH5uU9k23KCsRYAJvMdtv4DDmMFKRKVBBlL0KU6l3dWARRNCKQpdLTJp8RIhbM3jmfymK0NPsQaZ/FfIIosfW20Yco5hppqY4XRMnciAkpIci6QUONnjKXVh8i3XbbSHtLEaYohitnsjcTuHCzCMktG+ySVRdEpXPeEgRRuqQliJqbmw1Dg1xSX1+P22+/Hddccw1WrlyJkSNH4tJLL8XKlSuNbS666CLIsowrrrgCwWAQCxcuxB133AGr/uOUzD7MhE13veO9LfJBtAdRArvZfhiLQ7NFiEzUlJXDRYuSi5S5NHvuCFarJohKJNqQSaPaZMlNypx+vibTmLWE+xCZRRBJ1Xo9T19fwucTNa4eECFKojErT5ezila4rNqxTydlzkjHTTNCFHuTJtmbCbwxa7IGCVbqRUQQRBGRliC64IILcNNNN2Hq1KmYMGFCVgf00Ucfxf179uzZeOCBBwbdXpIk/PSnP8VPf/rTQbcZbh9mwq73xMinIEr0Yz8YxuIsZK7FWSppf/ki2ylzjLGMUuYA/fgFAqZLeUwXQ1i4chgh4ilzwewIIibLRg1eMseR19mY7SZEJvBol1nSW6VKzeFT8XgSPs+PV+xNI8ldHbdNMuLOozdlrbRWwCJqKdxKGilzop4yxyIRLf01xVosfiNBsDuSNu/hESJrkoLIpqfWUcocQRDFQNKCaMWKFXG9BA4cOICTTjoJtbW1hqMbRxAEvPDCC9kbZRlh1yNEke48CiIjZS6ZegYeIaKUueHg9SGqP7kIUfDz3Th4150YccYqVMwc2O+LhaL9otL9nKLVBgXRlKVix6ghymGESDAiRNk552OFVXI3IfSUuRI5ZkBMypzNHKYKUpUuiLwDBRFjLOENF4v+Gk4ygsgb0eqHqmwVkPQWBnI6KXMOh9H4WfX5IdakNo/p3FiRU4wQ2XiEiAQRQRBFQNKC6PDDD6fmanmgEClz0fz44VPmBDuvITLXjxx3mTNjylyyNURdTzyO0Oe70fff1xMKIoULK0lKeyFp1KOUyOJazTCFMBn4jYJkI0RMUeD/aDuch7YkjIBE787bk3Imi7rMmes7lwmGqUISaWb5wIgQeb1gjMX91rFwOHojIuYaKVgsEF0VRtpaMsfSa0SIKiEZEaLUBZEgihBdLqg+HxS/z6iBSpZUXA45aQsiSpkjCKIISFoQ/eY3v8nlOAgd+8gCpMyl4jLHI0Sms91OPu0vX/A0LiWJlDnF64V3y3va3z3ehNsYzmSu9Du/c0FUKovrqDlBPmy3kzvnOx55CN3PPoORXz0Ltcd/YcDzqRpBRF3mSmdhadQQ2UwiiHi0R1Gg+v2QdNMCIP64C7b4m0YWtxthLoiSihBp21ZYK2DJIEIEaNcB1eczoj2poOhjTiVCFEk7Za50zluCIEqXpP2yTzjhBPzqV7/CCy+8AK838YKNyByeMqd4+oxFQ64xLGWTSt/htttmFUTmSZlLxWXOs/EtQO94nyhtB8jMYY4jlJiFc9ScIJeCSPtesCRMFdRIGL2vvgoACB84kHibFNOVoi5zpXHMgOj5Z5YaItFqNW6m9K8jMvq02e0DmhnH9iJKRRBV2SqMCFE6tttAtI5IScNYIXotSf57k3qEiGqICIIoHpKOEB1yyCF48skncd9998FisWDmzJlYvHgxjjrqKMydOzftXkREPJaqKs0JLBKB3N0NW0NDzt8zFVMF0c4bs5rrR86MLnNSCilzfW+8bvx9MEGUSVNWTrRAvzTu2uajDxFPk0omQuR95x0jhWqwAn0lBYc5oDRd5sxmuw1oUSI1GNSOW1OT8Ti3W0/kwhkniJJxmYszVdB+ftNJmQNiehGlYb2dag8iIJ0IEU+ZK53zliCI0iVpQfSXv/wFjDF89NFH2LRpEzZt2oQHHngAf/rTn1BZWYnDDz8cixcvxuLFi7PuPFdOCIIAa10dwgcPQu7qzI8gSiHdTDRrhCgFUZcvknWZCx9sRfDTT4x/Kx7PgDoGICaykFGESE+ZK5HFdV5qiOzJu8z1vvof4+/ZivSJJd2HyBymCoAmiCLt7VC88dbbxrUlQUqxJUYQJRPt4qYKlbbMU+bECt3WP50IUSC1KCWQialC6Zy3BEGULinZbguCgKlTp2Lq1KlYvXo1AGD37t3YtGkTNm7ciHvuuQdXX301mpub8e9//zsnAy4HLHX1miDKk9PcUHdA+2OkXIXDCRfthcKMLnPJmir0vfFfAIDz0BYEPt6h2zIHIfRL/1OzUC8jlFiESEkj9SdVknWZC7e1IbB9W3Rsg0SIoovR5MZcammOAKCGTRgh0o0V5P4pc8YNo0QRoqj1dlK225HsmCoAMRGiNGqI1DQiRGmnzFGEiCCIIiDjPDdJ72EgCAKcTickSUIwS/06yhVrvWasEMmTsYIa4ulmSdhu26N3dM1U02DGlDnRqdeeyPKgERmmquh7UxNE1ctXGIuqRMYKqaZaJRyTYeFsnmOXLoyxPKXMJRch6nvtFQCARf/+KoPUWqbaTNYQsZEImO52VuzwCFGq/XNyCW+0OngN0cBrS2xz1lRc5qps0ZQ5BgaVqSmPl4sZxZd6hCidhsYR3S0uaUFEpgoEQRQRKTdmDQQCePPNN/Hqq6/itddew549e2CxWDBv3jx88YtfxJIlSzB9+vRcjLVssNbVAcif05yaUoQoug0Lh4EkXpMPTOkyFyMwVX8AYvXAxV9g58eQOzogOhyonDMXHZVVkLu7oHg9sI4cGbdtpk1ZgdKycGbhMKBqC8ncpsxxZ8XBBRFTFPS+/hoAoPYLJ6H9vr9D8XnBVHVAIX6qRhBijBMbi0RM07snEwzbbTNFiKqi1tuxGNfHBNcWI2VOFJNqcOqLRGuIeB8iAJBVBTYptfuT3AlPzcBUIbWUOS2SlXQNEfUhIgiiiEhaEN1+++149dVX8c477yASiWDSpElYvnw5Fi9ejCOOOAIOEy1Eix1DEOUpZS4VMSGIIgSLRYt6hEOQUDXsa/KBGV3mBFGE6HBADQa1RXB19YBtuJlC5fyFEO12SFWaIOqftgOkbteccEwlZOHM73JDFHMqEqIRosFT5nzvb4HS2wOpsgrVi5ei/b6/600zfVFLZ53UXeb6RWVLQhCZy3YbAKTKSgCaw2cszKghGtxUIRlhF1FlBBXtHNJMFaKCSGEygNTmIuoyl0bKHBflKZkqaMfMKiY3TupDRBBEMZG0ILr++utRW1uLH/zgBzj99NPR2NiYy3GVNda6PKfMBQdPCUmEYLdrgshETnNmbMwKaJELTRANXLSo4TC8mzYCANyLjgIQXZSpCdKteGPWzFzmSsfCOVYg5rKWzTBVGCJC1Kuny7mPWgzRbofodEINBKB4PQMFUaouc5IESJLWIycSwfBxCPOjmtRlDkiUMscj6AOvLbbGJghWK6wjhze/8Ya177QoiHBanJCEaERITqOOiAtqNYOUOV6HlAzc/CFWyA0FT5mLUISIIIgiIGlBdPTRR+Ott97CunXr8K9//QtLly7FkiVLMH/+fNhK4I6lmbDU85S5zry8X6oObaLNDtXnAzOR05wZU+YAPZrTHa3/icW3+T2ogQAsdfVwtkwBEF2Uyf3uUgPpOUP1p5QsnPNRPwQAgl5Mz8LhhClwck83fFs2AwDcS5ZpY6pyQw0EIHs8sDXH7y8d+3TRaoWqKCUhZIHYGqIiEERDmSpUVmLC1b9OKjLtjUmXEwQBgiBAEiUoqgIlDac5o4YoE1OFtGqIko0QaduFSBARBFEEJC2Ibr31VoTDYbz99tt49dVX8eqrr+KOO+6A0+nEwoULsWTJEixZsgSHHHJILsdbFvAIker3Qw0Gc7rIVyMRoyFosu8j2M1Xh8JMmDIHDG29zdPl3EcuMhbZ3OkqUUF+VhqzlpCFcz4st4H4yAALhwa4//X993VAVeGYfCjso0YB0BbKkbaDwxzH5M9VwWoDgsGSMMMATGq7XambKniTN1UAAGv9iKT2H9uDiGMRLVBUJb0IUUX6LnPp9CEyaoiEJCNElDJHEEQRkVIVp81mw6JFi3DppZfi8ccfx3/+8x9cccUVqKiowJ///GecfPLJWLFiBX75y1/marxlgeR0GoulXKfNsRgr4WRMFYBoLyKzRIiYqpo4QpTYelv29MH3wfsAoulywOB3qYEsNWYtIQvnfFhuA7qI1FPy+tcRMVVF76taulz10mXG40Mdx3QifUb/qBIQskA0ZdNMKXOWmGMW6+Y3lKlCKniMHkSV0ffU0+YU3dI6FaI1RKmlzDFFMeqiUjNV0CNEUpIRIr0xa4Rc5giCKAIyst1ubGzEqlWrcO2112LdunU4/fTT0d7ejoceeihb4ytbLLX5MVbgtTeCzZaUSxLfFhi+L0u+iBVmZhNEvNeM6o8XRMFdnwKqCtuoUbA1j4puzwu7EzT1zEpjVsNlrvgXKam6taWLIAhRY4V+dUTBTz9BpL0NosOBqgWHG49HI32JhG3q9umitXSELACosgkjRLogYpFI3I0iNkRj1lTwRbTvb1W/CBGQXnNWLmZYKAQmJy+oYm/OpPLdMfoQJR0h4rbbpXHOEgRR2qRsuw0ABw8exNtvv4133nkH77zzDnbs2AHGGKZOnYpvfvObWLRoUbbHWXZY6uoQ3r8v53VERmQlBftsw4bYJClzRn+YHLuNpQNfcCj9UubC+/cDAOxjxsY9PmRkIY00l/4IJdSHiIvMXNcQAXpz1kBgQC8ifhwdk1vivkNRYRufMscYS+s4llpzVn7tMFMNkWC3Q7BawSIRKB5PjAjmEaLMWgxwU4WKBIIoneasseeP4vdHLcCHgUdWBbsj6ZtggOaSB6TuMheixqwEQRQBSQuie++9F++88w7effddHDhwAIwxjB8/HkcddRQuuOACHHHEEahOYCtMpAe33s51ylz0xz75u59mixDFNmXNpdtYOgyWMscX0rHRIWDwGiI1EjbuAmcSESmlSEO+aogALTqgYOA5H+nqAABYR8TXkUSFbT8L55jeSVJKNUQlljJnQtttQRA02/suzfae9wGL3jTKNGVOryGyxQoiTZCkEyESRNFwM1T9PiBJQZRuPzMjQpRkHyKr4TJXGucsQRClTdKCaO3atRg5ciSOPPJIHHXUUVi0aBGamppyObayJn8pc6lZbgOxNUTmWFSbtX4IiDVV6CeIWgcRRIM5XfGUu5j0rXQwxGwJLKzzabUe7UUUHyGKdGoRXH4DgzOYsI3rnZRKVLbUIkQmtN0GtOMmd3XFpTpm6/rCXeYSpcylU0MEAGJFhWbvnoL1tppmLWI0QpTcssEeY6rAGDPdzSqCIIhYkhZETz75JCZNmpTLsRAxWHhz1lxHiNL4sRftJosQmdRhDohGAWJd5hhj0QjRqMQRItXvA1MUI6UlrueOmH7pn+EyVwIL62wVuyeDkSba75yXdUFkqR8sQtRP2MYsRlNZIAol1D+KqaoR7TSdIEpw3Ph1LhUBmwieMhdnqpBBhAjQ6gllpOY0x00Ych0h4jVEKlOhMAUWIa0MfYIgiLyQ9BWKi6FwOIzOzk40NzeDMYY//elPcdstWrQI8+fPz+4oyxBuvW1GQSToESKz2G6btSkrkDhlTu7u1uZdFGFriG9wzK10AUDx+Yy6gGw5qhmRhlKIEKXYPysTBjNViOg1ftb6+rjHBzPHiBpjpHYco/2jiv+4xRoAiCYyVQASm2Fk6zzz6qYK/W23gfRqiAAtQgSk5jSXju07kIYgEqPHNqyEk34dQRBEIUjpCvXMM8/gyiuvxBFHHIEbb7wRqqrij3/8Y9w269evxzPPPAN7hnfTyh2eMhfp7sppukHUQSmN9B3TRYjMKIi4qUJUEIUP6NGhhkYIlvivoCBJWhqMzwfF4zEEUbaakBoucyURIcqjINK/H7G220xVIXd3A0gQIaocLEKUusMcEFP7ZZKbEJkQ+xmKIULEr3OpXCMT4eW229aBNUTpNGYFoteDRBGiSEc7RIfTEOecdHoQAVFBlGzKnCRKEAURKlMRUsJwWXNf60cQBJEuSefebNmyBT/5yU8wb948XHjhhXHPrV+/Htu3b8fjjz+O9vZ2/POf/8z6QMsNnjLHQqG0Gu8lSzrpZtE6FHMszkwtiPiCJSZlzhBE/dLlOAnvUmehKSsQ4zJnkmOXCfk87rzGLjZCJPd0a02NJQmWfoYyhoVzOByXWpruYjTqDlgKESL9M0hSSi5n+aC/IGKMZcVUQWUq/BFNDFfFpsxJuu12uhEi3ouoXw1RpKsLn/3ycuy78YaBY0mjD5bKVCOtL5VIT61d+17s9e5P+jUEQRCFIGlBdOedd2LevHm45ZZb0NLSknCblpYWfPGLX8QzzzyTtQGWK6LNZiyMc5k2VxK224bLnIlriGL6EA3mMGe8JsFd6nQX0v2JusxF4ppPFiPpGIKkC7dcjjVVkDu176W1tm5AXZfodAL6Yl/xRY0VjMVoisI22j/KHN+5TOCGHoLFXNEhYKA7IAuHAf17konw9kX8YND247JEr1MZR4gqEkeIgjs/BguHEdz16YBaz3Rs32MFW7IRIgCYOWIaAGBz+4dJv4YgCKIQJC2INm3ahDPPPHPY7ZYvX45t27ZlNChCg0eJIt2560WUnu02ryGilLnhEBOYKgwfIRpYf5LuQro/hs0xYyk1czQjea0h0kUXi4kQccttS7/6IUC3cE6QNpdu/UYpuczxKJdoIsttjqUqPjobKyYy6XHm4T2ILC5IYjQqJolZihD1qyEK7vnc+Hv4YGvcc0oa0WY5xgUvlQjRYSNmAgDe79iadp0UQRBEPkhaEPX29qK5uTn+xaKICy64AA0NDcZjDQ0N8KVgAUoMTj6c5jJxmWMhcyzOzC2I9G7ysgxVj8qE9u8DkFqEKBtNWYFopAEo/sV1oWuIZMNye6AgAhI3Z+W1ZCmnzBkucyWQMqefd2arHwIAqVI3MfFwQcSjkPaM3B29CXoQAbERovRuTki6IFJ98RGiUKwgOnAg7rl0+hBxy20BAiQh+TTHyTUTUWFxwRvx4dPez5J+HUEQRL5J+gpfW1uLnp6euMcEQcCPfvQjjNQb2AFAW1sbRvRrUkikh9GLKJeCiP/gF3WEiBeqmy9lLnZMaiAAxeOB6vMBggBbU3PC1yTqYaME0oss9EewWADdoKPYF9csn4IogctcpHPwCBGQuDlruhGiqMtccYtYwLw9iIAENUTBbBkq6ILI2k8Q6eIi/QiRJmr6R4jiBFFrP0GUhiiPOsxJKRn8SKJEaXMEQRQFSQuiadOm4cUXXxx2u+effx6zZ8/OaFCEBm/2yK19c0E6BcPRGiKzCCLzRogEUYwW5Af8RrqcdcQIIw2qP5aEEaIsucwJgrEQLebFNZNlI+Uvv6YK0XM+wmuIBhNECYRtum6BYgn1IVINQWQuy20gGtVTg0GokUhWDBUAwBvmEaJ4xzfDdjvjGqKoIJJ7e6D09hr/jvQTRIoRIYoXZ0MhqxF9vKmL2MNGamlz77V/UPR1iwRBlC5JC6KVK1fiiSeewAsvvDDoNi+88AKeffZZfOUrX8nK4Mqd/KbMpW67rVLKXFJILl5HFBjWUAEYxGUuze7yiRBsUWOFYiXW3CDTxWoy8O9HrNW8bNQQJY6IS1UDa8HSqd8ASuOYcbioE00YIRJdLkBPjVO83iz2IBpouQ3ENGbN2GUumjIXGx0CEkSI0qkhMhzmUncFnFbXAptoRXeoB3s8+1J+PUEQRD5IujryxBNPxNNPP40f/OAHOOmkk/DFL34REydOBADs3bsXzzzzDP75z3/i9NNPx+LFi3M24HLCSJnrzp0gMvoQpWW7bbYIkflS5gA9Paq7WxNEB4auHwKGcZnLQlqgaLVBRXGnzPE0ScFqzYt1Mxdd/FxjjCEybA1RgkhfmsK2lFzmuO22GVPmBFGEVFkJpa8Piqcvi4JIi+BUDRBEvDFrhjVEMRGi0OeaILJPmIjQZ7sQbm0FU1WjBiodx8qIHiGyphEhsklWTK+fivfa38fm9g8wzj0m5X0QBEHkmpQas95www3485//jDvvvBNPP/208ThjDHa7Heeddx5++MMfZn2Q5QpPmZO7u+N+0LJJSdhu8xoik0aI+J1Yxe83CpwHc5gDEhfjR1Otkk9zGYxoTxtzHL90SMcdMRPEfilzqs9nRIss9XUJX2MIW28i2+1UXeZKqA9R2LyCCACkKrcuiDyGiYaQYQ2RL6Id94p+zUmNCFGaKXMiT5kLBsEUBYIkGRGiyjlzEd67BywSgdzVCeuIkVqqqS7yUknb5BGsdCJEAHDYyBl4r/19vNfxIU6ddGJa+yAIgsglSQuihx9+GMceeyy+//3vY82aNXj99dexZ88eMMYwatQoLF68GJX9OmJ3dXXh3//+N7785S9nfeDlgKWmFhAEMFmG4vEMaP6YDfgPfmq22zxlzmwRIrMKomjKXCiZlLkY61/GGARByFpjViDa/6WYow35PubRPkSaMOV1fZLbbfR26o8lYYQoXZc5PWWuiI8Zx6ghysDGOpfEff9Cqd8wSkRY0T6zXYrfD2/Mmq4ldawNvxoIQKqsNCy3HRMmwtrQiPD+fQi3HoB1xEjj/ANSizZnEiECgJn10yAKIlp9B3HQ345G18jhX0QQBJFHkg45/OIXv8CePXsAAA6HA8ceeyzOOeccnHvuufjCF74wQAwBwJ49e/CLX/wie6MtMwSLBZbaWgBA7ysv5+Q90kkJEXWXOSiKKXrZGItjE7rMAdFogNzVCaW3B0ByNUQsEjGiEFlNmSuBepR8C6L+pgqy7jBnHaR+CIhfWHMyrSEqZiMMDo9MmrGGCIhPdcyWqULEMCWIvweZaWNWwWIxzk3F54MaCiFy8CAAwD52HGx6qwwemebnn2B3pJRqarjMCSkllRi4rE5MqZ0MANjc/kFa+yAIgsglSV/dGGO45ZZbUKsv0JOhu7s7rUERUepOOhlt9/4fOv/5KCS3GzVHH5O1fTNVjRY4p/CDL9ijd3bVcBiSJb0fyWzAGIvedTdthEhb/AY+2QlAqw0bKmVKsNshWCxaZNDrgWC1ppXmMuj+S8CxLJommR8RzM8tFgqBqapRP8SNTxJhpD5yC2dFMQRu+i5zxStiOYbttsWkgihBDV+m1xYuKKxS/GfmAindlDlAc5qTQ0Gofh9CXg/AGKTqaliqqw1r/3Cr1pzVSNlM8fyLGLbb6V/rDxs5A9u6dmBz+4c4YXz2fscIgiCyQdJXt1GjRmHHjh0pv0H/Zq5EatQccyzknh50PfkE2v5+D6SKClQtODwr+4516kqpD5HFqvWyYUxbVGdhkZ4uLBwGdCtX8woibdEe3PUpABh3bQdDEARIVW7I3V1QPJ64RX82IkSlEG3g526mtR3JEpsyxcLhaFPWpCJEXjBVjU9XSvFcjbrMFe8x4zCTp8zF2t7zertMry1hI+Wsf4Qos5Q5gN9w6YLi9yPS3gZAiw4BiBFE8RGiVFM2DUGXgSCaPWIGHvjoMXzW9zl6Qr2osWc/BZwgCCJdkr66/fvf/87JADo7O/Gb3/wGr776KkKhEBYuXIjLLrsMkyZNAgBs27YN11xzDT744APU1dXhnHPOwTe+8Q3j9aqq4o9//CMeeugheDweLFy4EL/85S8xduxYY5vh9mF26r90BhSvB73/eRkH/norRKcLFTNmZrxfQxBJktawM0kEQYBgs4OFggWvIzI+gz4mM2LUEOmLkaEMFThSZaUmiLxeiHqkQbDZUjpOg47HqEcp3mhDvk0VBJvNuAmghoJGDdFgTVkBQKzQ04gZg+r3G811eQQwpfc3XOaK95hxeO2aeU0VooJIrNBMTDIV3lFB0T9ClJntNgBI+hhVn88wVIgKoiYAUUGk+tOLEMlZiBBV292Y4B6HXX27saX9Qywbc1Ta+yIIgsg22bctS5ELL7wQu3fvxm233YaHH34YDocD55xzDgKBALq7u3Huuedi3LhxWL9+PS688EJcf/31WL9+vfH6W265Bffddx/Wrl2L+++/H6qqYs2aNQjrP7rJ7MPsCIKAhq9/A5ULDgcUBftvuRmBTz/JeL+x7mypdB8HANHOF9WFFkT6Z7Dbc+LClw363421NY8e9jWxi7J0C/EHoxRc5li+a4gEwYgSqcHQsJbbgJbmxsWw4vXEGGOkHuUTS+CYcbjttulriOJMFXJVQ8Qbs6Zfi8mvC4o/KogcuiCy6hEipbcXit+X9jkYyUKECNDS5gBgc/uHGe2HIAgi2xR0Bdnb24vRo0fj6quvxuzZszFp0iR873vfQ1tbGz7++GM8+OCDsFqt+NWvfoVJkyZh1apVOOecc3DbbbcBAMLhMO68805cdNFFWL58OaZOnYp169ahtbUVzz33HAAMu49iQRBFNK/5DlwzZoKFQmi9PfPxcztgvgBIheiPsH+YLXOLkTpl0nQ5YKDF8nApc0D8oizdu7qDUQo9bQrhLBg1VggapgpDRYiA2Doib4x1eurHkR8zqKopjEwywfy22wlMFVJoXJ2IiJJYUBimCplEiHhzVq8Xob17AQD2ceO155xOSDU1ALQ6IiXNPljZiBABQEutlvlxwHcwo/0QBEFkm8JVwwOorq7G73//e+PfXV1duOuuu9DU1ITJkyfj5ptvxuGHHw5LTHrJkUceiVtvvRUdHR3Yv38/fD4fFi1aZDzvdrsxffp0bNy4Eaeccgo2bdo05D5GjBi8BmA4LJbs6klJEuP+HPiGNoxecx4+vviHiLQdhCQis6hIQGvmZ6mqSvmzWFwViABAMJD1eUgFQb9jLjmdGY1j2LnPAGtlfO8g17gxw47VWu0GAKg+LxCK9iDKxlxLenRPUOSCHjtOOnPP79xbMjzuqSA57FB6Afh9RsG9s7EB0hDvb6lyI9LeDub3AtBq3SSXK+Uxi87oglxkCiRLdupvcnneD4puQS057KY4//pjq9FqWxSvBxb9e2hN45jFIusRIofVZuxHksRohAhK2vu3VGnXl9CuT8HCYQh2O5yjmozfBnvzKPh7eqC0tQJ6RN1Skdq1RIEm2GwWa0bz4LJpNxUiasSUx54giPKloIIoll/84hd48MEHYbPZ8Oc//xkulwutra1oaWmJ266hoQEAcODAAbTqzjn9jRsaGhqM54bbR7qCSBQF1NZm3iQzEW734OkMaqUNH/Pt7AIslemPIaRqYsJRW53yZ9lf40YAgEOQczYPycAkFQBgq6zIyjiGmvt0ERvqsEf/u7W6GiPHNg37Gu/IOnQBsISDcAjaYsRRXZmVz9jrrkA3AJvICnrs+pPK3HfoKUYVdamfu+lirXAhDEDqaQegifD60SOHTDc9UFeDwKeAXQ1D0EWHo7oq5TEz5jJqmNwuC2w12f3MuTjvB+MgtO9sZXV2vrPZJiw04lNoNtaCnhLsHpHZecZd5EbUVaM25potdWkRIkFC2vv31teiC0DgY830qHLCBNTVR6P+XRPGwb9tK4TuDlgU7ZpfUV+T0vtZ7do5XuF0ZDYPNk1sRtSIKY89QRDli2kE0Te/+U189atfxb333osLL7wQ9913H4LBIGz9nIjseh5/KBRCQE9BSbRNb28vAAy7j3RRVYa+vuymi0mSCLfbib6+ABRFHXQ7wWYDC4fRua8dtobUan9i8RzU6iCYw4nubl9Kr1Wt2hx62rthS/G12aSvo0cbj8WW8meIJdm5T4egHD1G1qbmpMYZtmh3Uv0dXUC7Zl+vWO0ZfUZOSNXGE/D4srK/TEln7gO9WrpnSBXy9hmYHpXp3qG5BVrq6tDTM/Q1QLVrQsNzsMNIEVMs6R1HwWoFC4fR3dYDG8tOulkuz/vBCPm06F4gwkxx/vWHKXrkgjEEDmqubb4IgAzGyhuz+j0RdEe0/UiSCIveCygYDqc9F2HdqIGnL1tGj47fV51206/vs8+NHnIRwZrS+/X5tH2rEWR0zPwhbR4iqozOLg9EIf9RIrfbmd+IKEEQRYFpBNHkyVrTtmuuuQabN2/G3//+dzgcDsMcgcNFjMvlgkOvHwiHw8bf+TZOvW5juH1kgiznZgGhKOqQ+xZdLijhMMIeL8S6xBEuJRBA4OMdqJg+Y1BHq0hvHwBAcFWm/FkEvbdOxOvL2TwkQ8SviWLB4cjKOIab+3Rgtui5aW0eldT+Bb0uIOLxIOLVFiCCw5WdsUl6mk4wXNBj159U5l7h7oI2e94+A3caC+7bBwCw1NUP+97cITDS22cUsgsOZ1pj5oIoEghBzPJnzsV5Pxi8do1JFlOdf1EEiBUVUH1REwJmtaU9VpWpRuNVgYlx+zH6ECly+nPRrxeXdfS4uH1JDVpEOrT/AKwjR+qvSe16GdHr1kRIGR0zkUV/i4LhMGySOa3XCYIoPwp6m6SrqwtPPvkk5JgiYVEUMXnyZLS1taGpqQltbW1xr+H/bmxsNFLlEm3T2NgIAMPuoxjhRbTqEIYGnf98BPtvWoe+DW8Muo3iS99UgReGq77C3uE1e1NWIN7RKRlDBSC2h43HaKaYjR5EQGn0tCmkqUJ4vy6IhuhBxImaY3ijPWDSPI5iCRw3IKYPkUlNFYDo94+Ticscd2gDANtgttsZNGbtb5DALbeN9+S9iNoOGrVvqZoqRAbpo5QqtpjGtDxqRhAEYQYKKog6Ojrw4x//GG+8EV20RyIRbN26FZMmTcLChQvx9ttvQ1GiPxZvvvkmJk6ciPr6ekydOhWVlZXYsGGD8XxfXx+2bt2KhQsXAsCw+yhGYm1WByOii77IwcHdfKIuc6nnciczhnxQiIVxqsSOzT5qeMttIGYh7fFA9afvTpYIw2UuUrwLkuhxz1/tC3ca4yLcWlc37Gv4wlqOsU9P9zgKJdA/Coied4ZzngmxVLnj/p2JyxwXE8AQtttZcJkDAAgC7KPjrzGW2lrtJoiiILRv78DXJAHvk5Spy5woiJAETQTGzgtBEEShKaggamlpwbJly3D11Vdj48aN2LFjB372s5+hr68P55xzDlatWgWv14vLL78cO3fuxCOPPIK77roL559/PgCtdmj16tW4/vrr8eKLL2L79u24+OKL0dTUhBNOOAEAht1HMWJEZ4aIEPG70XJf3+DbeLW7helFiIaPUuWDQiyMU0WwWGAdMRKCzTbg7u1g8IW06vcbxylbfYiMnjZFbbutp0pm2B8mFfpHCVKLEMX2IUpXEGnHTS32CJF+3pm1DxEw8JqYSYSIW1ZLgjSgZiYaIcqkD1FU3Niamo1+WRxBFI0okTH3KZ6D0QhR5seMR4nCJIgIgjARBa8huuGGG/D73/8eF198MTweDxYsWIB7770Xo0aNAgDcfvvtuOaaa7By5UqMHDkSl156KVauXGm8/qKLLoIsy7jiiisQDAaxcOFC3HHHHbDqP7b19fXD7qPYSKYHEE9lUzxDCCJPKfQhMn/KHACM/dn/gxoMGn1phoN3nwdjiHRoPW+yljLHIw0lESHKrD9MKvRfaFqTiDDHpj7yczRdYWukzBWxkAViUuZs5o0QSVXx39NMxspTwxKlm0UjROnX5UgV0fPJPi7xDRdbUzNCn+82/p1yHyLGI0RSGiOMxypaEUCQUuYIgjAVBRdEVVVVuPLKK3HllVcmfH727Nl44IEHBn29JEn46U9/ip/+9KeDbjPcPoqN5CJESQgiXkNUldwiPW4MFWaLEJlbEFlqalPaXpAkiK4KqH4fIu1a+mPWUub0CFExN2ZlujFKPo97//dKLkIUbczKo6rpClseISpmIQtEI1ymriGKuUkk2O0Z9XvjEaJE0RVDEGVUQxSNEA0Wge5fu5jqtYRHiCzZiBDp+6CUOYIgzAR5TxYh/AdwsOgMYywaIerzJN5Glg0xI1WkLoh4yoV5aojMmzKXLjy6wBfA6aZa9Ue0FndxPpNlMO56lVdThZgIkSTBUl097Gv4wpqFgsbNibRriPQoRTELWSDmfDazIIoxVcj0HIuKiUQRIj1lTs0gZc5qNc6NQQVRU7wgSlWU8xoiq5CFCBFPmVOK+zwmCKK0IEFUhEQjRInFCAuHjQWjPEiESOHucIJmMZsqYsXwUap8UAwuc+nSP70uW4LIcJkr0uJ8LoKBzGo7UiX2vay1dUlFDUSXC9C3k7u1flLpHsdiF7KcYnOZy/Qc4y5zVmmIlLkMIkQAUDlnLqxNTXBOmpzw+VhBJNgdEKTUhI3MRZ2U+TGzUoSIIAgTUvCUOSJ1xGFS5pQYK2wWCkENhQbUP3CHObGiIq10EJ7+w8XXYL2Ock2xpMylQ3/r3+y5zBV3cb5hqGCzpbywy4TYc8ySpEOlIAiQKiuhxJibpFtDJBhmGMW7kGSMFYkgirrM9b92pspQhgTRCFFmgqj5O98FYwyCkLhRt7WxERAEgLG0riM8gmXJQoSImypEMoiKEQRBZBuKEBUhw6XM9Y8cJaojivYgSj1dDohPuVAK2ItIDemCKEuGA2ZigNNV1lzmirs43xDBeYwOAfEGDskYKnCkfhbOUto1RNwuvTiPGwBAUQDGAJjbdjubKXO5riHiDCaGAO07z0V8OteRyBCfIVX4PihljiAIM0GCqAgZzlShv0CRE9QR8QZ96dQPAZqVKxchvHFoISjplLnYCJEkZe2OerG7zBXCYQ6IF2CWuhQEUexNB1GMr0VK5f15hKiIBVFs/ZOpI0T9TBUyISomBq8hUpkKlaXvNJcMPG0unQjRUGl/KY+DUuYIgjAhJIiKkOEsr/sLooQRIt6UtSp1y+0B4yhkhKiUU+ZiFtKSyzXkHeBUMFKvZBksA7vfQqEWwGEOiF8YpxQhijmOYgbHsRQasxoiXBAKlmabDLHOmxmbKiiDmypIMTbWmTRnTQYuiNKJpkdT5jI/ZtxUIUK22wRBmAgSREWIESEaJDKTVMqc0ZQ1vQiRNo6KIceRa9RIREvBQWkKIktsHUOW0uWAaHE+UJxRomjvqfymScZFiJKw3ObEpsylmy4HxLjMFXGEiMVYbmdL4OcC0Wozmv5mbqowVA1RVGDIWUibGwrn5EMBDLTgTgZDECUQdanCI0TUmJUgCDNh3lt0xKDwxTELh6FGIgPsawdEiPoGCiLVm35TVmMcujud4iuQINIXxkBp2m6LsZGFLDnMAfFNJlkkAmSYEpRveFRQKGQNUZopc5kcR/49L4UIkZnT5TiWqipEQsEsmCoMkTIn5C9CVDl/AcZfuXaABXcyZFMQWSXt+kMRIoIgzARFiIoQ0eHUHIOQuI5IHVBDNETKXJo1RAAgOYe2/841xsLYZsuocaJZscSkM0rZFESiCOjubMXY06ZQaZKiywXBbofocMBSX5f06+IK9DOI9Bl26UUcIVKLSBDx45ZLUwVRFCEKui07y63rmiAIsI8Zm1aq4lCiLlUoQkQQhBmhCFERwg0NVL9fEyP9GkTyCJFgd8Q1hIzbhqfMVaUviHgvosFqmXINK+H6ISA+eie6shsBE202qIFAUS6uC2aqYLVh7CWXAYIYl3Y4HLHHMRNha7jMFaGI5RRDU1YOF0SZmiqEjR4+iX9uJUGCytScR4jSRWWq4YKXlQiRvg8SRARBmInSu61eJgxlrMAjNramJm2bRC5zWUiZK3SESOEOcyVouQ30iyxkMUIERO/QF2P6FSuQqQIAOCYeAseECSm9Jv44pn+uRl3miu+YcaIpc+a13ObYx0/Q/hw9JqP98AiRbRDLaqMXUY5riNIltkdSViJElDJHEIQJoQhRkSK5KiCjI6GhAY8Q2ZqaEdr9GeShXOYyMFUwaogKFCEqVD+afCHY7RAsFjBZzlpTVmPfRVygHzVVKI7j3t9lLl2iLnPFd8w4PLpVDClz9aeejuoly1JyFEwEN1UYLLrC64jMGiGSYxqoZidCRClzBEGYD4oQFSlRy+sEgkgXKNxNKHcuc0P3Q8o1pZ4yJwhCtI4hy4JILOLFdVQIF0dkMC71MSOXOW0hqZZAhEi0mT9CJIhixmIIGL7+Rspic9ZcwMcvQIAUYwKRLjay3SYIwoSQICpSoulqiUwVtOiPkTLn8cT1m2GybDQ0zchlrsB9iJRgaafMAdHjk+3PaKTMFeHiuth6T8XW6WUS6StmEcvhYxcs5o8QZQu+8E9kqgDEpMyZPEJkEaWsWKVbqTErQRAmhARRkcINDRKnzOkRokbdXlVV44STogsmCEJGkQeR9yGiCFHOsNRpbmaW6pqs7pcLomIs0C82QRTX0yYTU4UScJnj1x6psqLAI8kfQ7nMATCiLmaNEMlGyl92RCxvzBqmCBFBECaCaoiKFB4h6h+dYapqiCTJ7YbockH1+yH39RnpcYpXe41UUZmRXXWhU+aKbWGcDiO/fCZcU6ai4rA5Wd2vWMSL60K5zGWC0dMmoxoiLmKLdyHJe6LFNqstdYZLmeN1ObG1OmZCNhzmMk+XA6LmEhQhIgjCTJAgKlK4oUH/CJEaCACMAQCkigpIVW6ofr9eRzQKQLR+SMzwLi2PEBXMVIG7zJVgU1aOrXkUbM2jsr7fYnaZUw2XueI57vZx4xDp7IB9VPrHsphFLIcbvEjuchJEQ5sqSKK5I0RhRTvfBnPJS5WoqULxnscEQZQeJIiKlMHqd6I9iDSHMovbjcjB1jhjhaihQvr1QwAgxaTtMVXNe3NUNVT6EaJcUQouc0IRuQs2f+e7kPv6YK1LvqFrf0rBZU7x8P5n5SeIeKpYf7jLnFlriHhqG7fLzpSoqYI5I2IEQZQnVENUpERNFQJxj/OeQJIeQeIuZTxVBciO5TYQ43zGmLFIzSflkDKXK6IF+kUYISrC4y5YLBmJISDqMsdkOc4kpZjg1yGLO7ObMcXE8C5zJo8Q6ZGcbAkiMlUgCMKMkCAqUripgtIvZY5HiHg6G78TK3uizVmz0ZQV0IvFeV1DAdLmZF6PkKGwK0eMxXVRRoiKTxBlAzGmmWkxugMC0RYA5RQhGs5UIRohMmfEJJTllDmbYapQfNcegiBKFxJERYrk1GuI+qXM8X8bESI9Vz8XESIgJnWvEIKouwsAYKnN7M57OcLTr4rNZU6NRABFu5NeboJIsBW/IJL7yjBlTkmyhsjkKXP2rEWItP1EVBlMr3clCIIoNCSIihRDiAwSIZL0CJGFp8wlrCHKXBBJBbLeZoxB7tIFURaaJ5Yb0QL94lpYM91QAQBEe/G4zGUDQRQBSVs8F5uQBTQzDKbX/ZWXqUKSLnNmTZlTspsyZ5O0z8vATBsVIwii/CBBVKQYhgZ+f9xdNt7nQ+wfIYpNmfNkJ2UOKFxzVsXrMRbzlpravL53KRBtzFpcC2vDUMFmgyBlxwa4mChmpzl+I0awWMoqumeYKgzXh8isESJeQyRmt4YIoDoigiDMAwmiIsVo8Kiqxl1XIBqp4YLJqCGKSZlTfdlLmYv2IsqvIOLRIcnthmgtn6732cJwmSuySINRP1REDnPZpJjt0uVebrldDUEQCjya/DFsDZHZTRWyHCGSBAmioC09wiSICIIwCSSIihTBZoNg0VIPYut3jJS5Ck3scEGUq5S5QvUiMtLl6ihdLh1EI0JUXAuScjVU4BSzXbpShj2IgOii3yoNnTJn1giRYaowiG14qgiCYKQP8vokgiCIQkOCqEgRBMGIEqm+GEHk5y5z2nMWffGh+v1gsnanMlsuc7Hvk+8aoohuqJCplXG5whfWxdbTptwFkVjEvYi4IOJ1jeWAoipQmWaRPqipAneZY+asp+GCLlsRIoCstwmCMB8kiIqYRMYKar8IkehyAXrDVNnjAZNlqAGtDiMrKXMVhXGZkzs7AQAWEkRpYbjMUYSoqBCKNLIHRJ0uy8lhLtYoYTDbaovpXeY08Z0tlzkgKq5IEBEEYRZIEBUxscYKnGgfIu05QRSjzVk9fYbpAgQh2lg1kzEYLnN5riEiy+2MEHkfoiKLNKh6vZxQrjVERVr7BUR7oZVTylwkJiVs+AiRuQVRtvoQAdEIEaXMEQRhFkgQFTE8ZS7W4Y0LEx4hAmLqiPr6oulyFZWajW+mYzBc5vKcMtfFU+aohigdeISo2NzKyj1CJBbpcQNiI0TlkzLHIyCxRgL9MXsNERct2UyZ4/VIFCEiCMIsJL5lRRQFhsNbIEGEqCIa/bFUuRGGFiHiRgzZSJcDoqYKaqBQpgoUIUqHaKShuBYk5S6IBFvxuswZNUTlFCEaxmEOiDZmNWuEKJRllzmAIkQEQZgPEkRFjNivKaoaiRgpUJLehwgAJLd2R1bu6zMiA9m6S2uIsjz2IWKqCrmnGwC5zKWLWLR9iMpcEFlLwGWunGqIhmnKCsT2ITKnqUJEzX7KnI1MFQiCMBkkiIoYI11NT5Mz6ngEAaLDaWwXtd72GAtJMWsRooHGDrlG7ukBVBWQJFiqq/P2vqVE1GWuuBYk5S6IxCKOEMl9ZVhDpC/4B6sf0p4ze4RI+wzZNFWw8pQ5ihARBGESSBAVMVK/CFGsoUJsfRBPUVH6+oyFZGyNUWZjyH+EyDBUqK7JSh1UOVKskQbehLh8G7MWZw0RU9WyjBAZKXOD9CACAItQHC5zWa0h4ilzFCEiCMIk0GqyiIlGiPSUOd3YgAslDk+Pk2NNFbJcQ8RkOW/OV9xy21pP6XLpEusyxxgr8GiSp9wjRMXqMqf6/VpUF+XVh4hHiIq5hiis5qCGiCJEBEGYjIILop6eHvzyl7/EsmXLMG/ePJx11lnYtGmT8fwbb7yBM844A4cddhhOPPFEPPnkk3GvD4VCuOqqq7Bo0SLMnTsXP/nJT9ClF9wnu49iRerXFJVbaosV/QURT5nrg+LV01aytCgRHQ5AEOLGkWsiZLmdMTzSAMYAxZwLsUSUuyASi7QPkaw7zIkul2HsUg7ISZgqRF3mzFlDlAvbbYoQEQRhNgouiH784x/j3XffxQ033ID169dj2rRp+Pa3v41PP/0Un3zyCc4//3wsXboUjzzyCL7yla/g0ksvxRtvvGG8/sorr8Rrr72Gm2++GXfffTc+/fRTXHTRRcbzyeyjWBkQIdL/lPoLInesINJtubMUIRJEMWr/nadeROQwlzncrQworuas5S6IjNqvIkuZK8d0OSDqopaMqYJswpQ5lalG2l9OXObU4jqPCYIoXQp6q2737t14/fXXcd9992H+/PkAgF/84hd49dVX8cQTT6CzsxNTpkzBxRdfDACYNGkStm7dittvvx2LFi3CwYMH8dhjj+Evf/kLFixYAAC44YYbcOKJJ+Ldd9/F3Llzcffddw+5j2ImGiHShAiPEPUXRLE1RIpbjxBlqYZI25cLqt+XtwgRCaLMESxWLbLHmOZM6HQO/yITUPaCSI8QFVvKXDlabgPRCFEypgqKCVPmYm2xs2mqYPQhUswZFSMIovwoqCCqra3FbbfdhlmzZhmPCYIAQRDQ19eHTZs24bjjjot7zZFHHolrrrkGjDG8/fbbxmOciRMnorGxERs3bsTcuXOH3Yegp3ulg8WS3QCbJIlxfw6HtUoTNarfD4tFBNOd3iyVlXFjE2trAGh1PnJHOwDAVuPO2vglVwUiaAeCgazPSSLkbq2GyDFyRPY+Q4pzXwoIVitYOAxRlfNy3AYjlbnnpgrWCldBx1woLA679hc5O8csX+c902sXLdXVZXXcFEETOXaLbcDn5nNus+giF6rp5kaNESwOm23Q5rKpYrdo4kpmEdN9ZoIgypOCCiK3242jjz467rFnn30Wu3fvxv/7f/8Pjz76KJqamuKeb2hoQCAQQHd3Nw4ePIja2lrY7fYB27S2tgIAWltbh9xHXZpRBlEUUFtbMfyGaeB2J3e3PiKNxCfQ7prXuB3o1nO9K+pr+o2tAqLDATUYNEwV6kY3wJml8durqxAE4BDknM1JLEq31oOobsJoVGb5/ZKd+1JAstsgh8OoclrgysNxG45k5p6FQwCAmoZaU4w534RrtNo/C1Oy+l3L9XnviQQAABUj6/JyjTAL1nbthpvL4Rj0c1fxJtoCM93cRLzacbNLNtTXZc8Mo7pS/5wW831mgiDKE1NVt77zzjv4+c9/jhNOOAHLly9HMBiEzRYfpuf/DofDCAQCA54HALvdjlBIWzgNt490UVWGvr7spohJkgi324m+vgAURR12eyZH3cE69rfD19kDAIhINnR3x9fzSFVVRroRAPhUC4Ld2an5UW1a+pKnvRvWLO1z0PeKRBDp7QUABCwuRLL0fqnOfUmg35nu6ehFqLK2YMNIZe5lv7ZA84YZQjk+18xIIKJ950P+wIDveDrk67z3tmlRXdnmzMq4i4VevWaTyRh4TdbnPhzUokihSNh0c9Pm6QGgmSBkc2yy/tPrC2TnPE4Ft9tZVpkABEEkh2kE0QsvvIBLLrkE8+bNw/XXXw9AEzb9RQv/t9PphMPhSChqQqEQnHpNxHD7yARZzs0CQlHUJPctQrA7wEJBhPt8kPUfXzhcA14vVVUh0q6ly0EQoFrtYFkav6DPY8TjzdmccMLt2sJKsFrBEnzOTEl+7osf7jQnB0Km+MzDzb0aiRiOeKrFZoox5xum97NRQ+Gsfv5cn/f8JoZYWVVWxy0kazU4kmAZ9HMLTIsiRVTFdHMTiGg3Fq1Sdr9vEtPqpkJyds9jgiCIdDHFbZK///3v+MEPfoBjjjkGf/nLX4wUuObmZrS1tcVt29bWBpfLhaqqKjQ1NaGnp2eA4Glra0NjY2NS+yh2Yo0VVH9iUwUg3t1JqqzMakPT/g1ic4ncpQkiS119RvVfREyBfpE4lrGYCGfZmioUqcsct90uN5c5bqowlGW1mW23c9GUNXZ/EbLdJgjCJBRcEN13331Yu3Ytvv71r+OGG26IS29bsGAB3nrrrbjt33zzTcybNw+iKGL+/PlQVdUwVwCAXbt24eDBg1i4cGFS+yh2Yq23Fb0xa/8+REB/QZRdIdjf/juXcIc5KznMZYzIF9dF4ljGUz4Fmy2rgr6YiLrMFddC0rDdLjOXOd54NBmXOTM2Zg3loAcRELUhJ0FEEIRZKOiqYteuXbj22mtx/PHH4/zzz0dHRwfa29vR3t4Oj8eDs88+G1u2bMH111+PTz75BHfeeSeeeeYZrFmzBgDQ2NiIk08+GVdccQU2bNiALVu24Mc//jEOP/xwzJkzBwCG3UexE9ucVfXpPYYSCKJYu9ts9SCKjkF7v3z0IYrwCBE1Zc0YociafBqW2/byjA4BMSK2yCJEih4hspRAVD4V+II/mT5Eign7EHHb7WxabgNR2+1YW2+CIIhCUtAaomeffRaRSATPP/88nn/++bjnVq5cid/85je45ZZbcN111+Huu+/GmDFjcN1118X1D1q7di2uvfZafP/73wcALFu2DFdccYXx/KGHHjrsPooZIzrj8xmCRHQlihBFFyJilgWRWBEVZblG7qYeRNmi2HraqKHy7kEEROu+WBFFiNRIBGpAM8Mot5Q53tTUOkSERTJxhChXKXNWkVLmCIIwFwUVRBdccAEuuOCCIbdZtmwZli1bNujzLpcLV199Na6++uq091HMcEEkd3cCqlacmrCGKKcRovgGsbkk0slT5upz/l6lTrHVo5R7U1YAEGzFVfcFAIpHawYNSTKuV+WCnIQgshgRIvPVEIXU3KTMUYSIIAizUZ6J+CUET1eLtHcAAASLxUiridsupzVEPGWOIkTFhFhk0QYSRLHHLAzG2DBbmwOjfqiyquxqv8LJpMzpz5kxQsRroLIfIdIEEUWICIIwC+X161SC8DuukQ7NUlusSBz9sVTlI0KUT5c5EkSZUmzRBhJE0WMGxgwLcrPDBZHFXV71Q0A0QpSMqYLKVNOJ3FDOXOb0CBEJIoIgTAIJoiJHcuqCqF2zFpcqEqekSDGLkWwLIh4hUgMBMDV3PSWUQMCoRSCXucwx6lFIEBUN/JgBxVP7pfRpKXOSu7rAI8k/hqmCNHzKHAAoJosShXnK3BDjTwceIVKZakozCYIgyg8SREUONzTgLk7SIBGi2DS5bKfMSTF1AbmMEnHLbdHlgujIrKkuAYh6tKFoUuZ0UwWhjF3mBIsF0PtvFYuQlXnKXJk5zAFAROE1RMOnzAGAbDJxYLjMiVmOEMXUJFGUiCAIM0CCqMiR+hUpD1a0LEiS4S6X7QiRYLEYBfq5rCOSu8lyO5vwaAOlzBUPgiBE7dKLRMhGLbfLy2EOiLXdHqoxq4kjRDlKmbOIFggQ9PcojvOYIIjShgRRkdPfYjuRwxyn7qSTUTl3PhzjJ2R9HPx9cxkhilBT1qwSbcxaHAsSEkQa/OZDsQhZI3pdZk1ZgeRqiERBNMSB+SJEuRFEgiAYc0LGCgRBmIGC2m4TmTMwQjSEIPrCScAXcjMO0ekCurtz2pyVDBWyS7Qxa3EsrBkJIgCa05yK4hGy0ZS58hNEvA/RcLbVFlFCRJWhMHNZbxu221kWRNo+rYioERJEBEGYAooQFTn9U+SGihDlkmiEKJeCiFtuUw+ibGBEGoqkOJ8iRBrcaa5YhGw0QlSGNUT6Yn+oCBEASIJuvW2yCJFhu53lPkRANI2QR6EIgiAKCQmiIqd/REgskCDiwiyXNUSUMpddjJ42keK4Q2sIojI2VQCikZbQ/v0FHkly8MasVEM0OLyOyGw1RNx2256jCBEQjaIRBEEUEhJERY5otxuuU0DhIkRcEKm+XJoq6BEiMlXICkakoVgiRCGKEAFA5WFzAADeTRsLO5AkYIxFG7OWYQ0RX+xbpeEiRJogMluEKFpDlLsIUYRMFQiCMAEkiIocQRS1+h0daYgaolwiGb2IciOIGGOUMpdloi5zxbEgoZQ5jcr5CwEA/o+2GdEXs6IGAmCyJgqybfdvdhRVgcq0vmzDRYgkI0JkrmgJt8TOSQ0RT5lTi+OGDEEQpQ0JohIgthlrwVPmfLmpIVK8HiO1y1Jbm5P3KDeiLnPFsSAhQaRha2iAfdx4QFXhffedQg9nSHh0SLA7tGh2GRGbCjZUHyIg2pzVtBGiLPchAgCrLrIoQkQQhBkgQVQCxEWICmWqwFPmcmSqwKNDktsN0Zr99I1ypNhc5kgQRalaoEWJPG+bO21O6dPrh8rQUEGOEUTDmirwCJFZBVFOIkTanFBjVoIgzAAJohIgVgQVKmWOmzvkylSB0uWyT9RlzvwLEsaYUUMkOJwFHk3hqZy/AADg37YVitdb4NEMTnlbbusRbUGCKAz9U2tEiExkqqAy1RAruTBV4BEiEkQEQZgBEkQlQKz1dn8b7nwRjRBlXxB5t7yHtn/cCwCwjhiZ9f2XK6IRITL/goTJMqBoi8VyS71KhK2xCfaxY7W0uffMmzan9PUCKFdDBW65PXxEW9KjJYqJHNfiU/6yH5W3kakCQRAmghqzlgA8ZU50OiFIUmHGoEepIl1d6H31P1BDYbBwCGokAktNLWxNTbA1NUNyuyEIAtRgEMHPdyP02WcI7v4MTJHhmjoNrhkzYRvZAACQe3rQdv+9hpuWpb4e9aeeVpDPV4rwCFExpMzxpqwApcxxKucvRGjPHng2bUT1kmWFHk5CDMvtshREusPcMOlyQNRlTtFNGMxAbH+g3LjMUcocQRDmgQRRCcBNFQplqKCNoRIAoPT24ODdfxt0O9HphFRZhUhHO8BY3HNc+FhHNsB56KHwvvsO1EAAEEXUHn8C6k9bSdGBLCLE9CFijEGIsW83G7x+SLDZIIgU2AaAqgWHo/OxR4y0OamystBDGoDcV74pc7yGaLj6IW0bXkNknggRF0RW0Tpsyl862MhUgSAIE0GCqATgEaJC1Q8BgG3UKFQvX4Hwgf0Q7XYINrv2p0VCpLMLkYMHEOnogBoIaCIHWj8h+/jxcIyfAADwb/0QgU8/QaS9DZH2NgCAfcJENH7jHDjGjS/URytZRFv0ri+LRIyIkRkhQ4WB2JqaYBs9BuF9e+Hd/C6qFy8t9JAGoJR1DZEmbpKJrnBTBTPVEEUtt3NjYmP0IaIIEUEQJoAEUQnA63cK5TAHAIIgoHH1N4bcRo2EEWlrg9LXB9uo0bBUV8c9X3/q6VACAQQ+2o7Ajo9ga2qGe8lSigjkCB4hAoDPrvhZXINfg9ggnihAEERAFCFIIiCIECRJS9MUReNPQDsfwP8DtGggG7h7CIAgCthvtUBWVDAI2j4EQduHKEIQBMOsQyRDhTiqFixE57698G7aaE5BxCNEZegyxyMfSUWIBF5DZCJBlEPLbSAqiMIUISIIwgSQICoBnFOmQXK7UXHY3EIPZUhEqw320WOA0YNvIzmdqJwzF5VzzP1ZSgFBkmBraka49YDh4md2LDU1hR6CqahasBCd/3wUvq0fQvH7CholToRRQ1SWESJtoZ+MIYEZI0ShHFpua/ulCBFBEOaBBFEJYB89Gof8/kZT14AQ5mTcL65EeP8+ALElXQyAdi4Jgv4/xsAYA1QVTFVj/lTAZCX6d0XVXs8jQozpu9LPzZj98YiRKAqocFnh84agKAqgxrwXUwFV+zsAVJBQjsPWPCqaNvfuu6hevKTQQ4rDsN0mU4Uh4bbbZqwhsuc4ZY5MFQiCMAMkiEoEEkNEOoh2OxwTDynoGCwWEbW1Feju9kGWzeOyVSxUzV+Azn170fPi85rNNWOaQAWiKpcL2n6IogCPy45gWAGDngopSnpKpKClRYran7HCVkuJhK59mf4XfaeCoL0GAlS9R1I51hDJhiAqzghRtIYoxxEiSpkjCMIEkCAiCIIoYioXLETn448h9PluhD7fXejhDEQUTemAl2vCRspcCrbbJqohCuWphohS5giCMAMkiAiCIIoY+6jRaPj62Qju+lSP5GjRG8PYwkhXFIy/ckRBgM0qIRQIQZVlMEUFUxRAT1XUUhZVMJWHf9gAu3z+HrH+GWCqnhbJUHHYnLI0RknHdttMEaJInmqIyFSBIAgzQIKIIAiiyKk55ljgmGNTfh2lK+aOlEwVTBwhsudIEFGEiCAIM1F+t+0IgiAIIsfw2hhrEqYEPIokMxOZKqjJjz8djAgRCSKCIEwACSKCIAiCyDKpuMyZMUJkuMzluoZIfx+CIIhCQoKIIAiCILJMWjVEJhREtlxFiAzbbfNExQiCKF9IEBEEQRBEluG1MbZUaohMZKrAzQ5yZapglShCRBCEeSBBRBAEQRBZJpJShEjbxkyCKKTm2GVOT8WTmQKVkaEHQRCFhQQRQRAEQWSZdFzmzJQyF8l1H6KYVLwIpc0RBFFgSBARBEEQRJZJxVSB1xApJnKZi9pu56aGKHZewpQ2RxBEgSFBRBAEQRBZhpsqJGNbbcYIUa5riERBNFIFqRcRQRCFhgQRQRAEQWQZLihScZkzle22mtuUOSDWepsEEUEQhcVUgujWW2/F2WefHffYtm3bsHr1asyZMwcrVqzAPffcE/e8qqq46aabsHTpUsyZMwfnnXce9uzZk9I+CIIgCCKbyKn0ITIas5pIECm5NVUAYq23SRARBFFYTCOI7r33XvzhD3+Ie6y7uxvnnnsuxo0bh/Xr1+PCCy/E9ddfj/Xr1xvb3HLLLbjvvvuwdu1a3H///VBVFWvWrEE4HE56HwRBEASRTVIzVdB+ik0VITJS5nJTQwTEWG+TICIIosAMf+sqxxw8eBD/+7//iw0bNmDChAlxzz344IOwWq341a9+BYvFgkmTJmH37t247bbbsGrVKoTDYdx555245JJLsHz5cgDAunXrsHTpUjz33HM45ZRTht0HQRAEQWSbVASRReARIhOZKqjcVCEPESJKmSMIosAUXBB9+OGHsFqtePzxx/GnP/0J+/btM57btGkTDj/8cFgs0WEeeeSRuPXWW9HR0YH9+/fD5/Nh0aJFxvNutxvTp0/Hxo0bccoppwy7jxEjRqQ9dosluwE2SRLj/iwmVJWhxxtCKKKAMUBlDIwBjDEIggBRgPanKMBmEVFTZYcoCIUetkExz30mhCIKAkE5erygHbP+CIKA6gobrFk+54HynXszQHOfO3jKnMNmS/hbETv3Nqv2+6QyJeu/K+nAGDPqepw2e87GxKNPCmRTfG6CIMqXgguiFStWYMWKFQmfa21tRUtLS9xjDQ0NAIADBw6gtbUVANDc3DxgG/7ccPtIVxCJooDa2oq0XjscbrczJ/vNBqrK8On+XryzvQ279veioyeAjp4AujwhqOrAhfRg2G0SRo+sxNiGKoxtrMSEZjemTqhDdaU9h6MfHjPPfSZ09ATw3o527Nzbg/buANp7/OjoCcDjT/7OrCAAtVUONNa50FDrQtMIFw4dU4OWcbWodTsyHmOpzn0xQHOffWRo6W/1NVWorR78t8LtdqI2XAkAUAWWs9+VVAjLYTBo1/PG+lo4rZl/vxPhsmv7tTklU3xugiDKl4ILoqEIBoOw2eLD9Xa7tmAOhUIIBAIAkHCb3t7epPaRLqrK0NfnT/v1iZAkEW63E319ASiKeTp3h8IK3tnRji2fdOKDTzvR60vcM0IUBDjskhEREgUBEKBFjFQGlTGoKkNEVhEKK/h0Xy8+3dcbt4/mehdaxtbg0DE1aK53ocJpRYXDggqnFRaJ59mrCEdUYz/+kIxASIYvGEEgJMMfkhEMKQiEZATCCoIhGQ67BSOqHfp/ToyocaC6wgZBj1KZde7TJRxR8MGuLnzwaSc+3NWFA52Dn6uCfqwEPYonAEC/4J2qMsgKQ1dfEF19QWz7rCvu+Tq3HZNGV6Ox1gVJFCCJWjRQFKM70gJPTH9PwXhPiySiqsoBp0VAdaUNdVUOVLmsxrEh0oMx7ZgFwzJCYQXBiAJZVmG3SXDZLXA6LHDarSV13puJsKzdbAh4I+hWfQOej73m+L0R4zXd3QO3zTfecHQMfk8EQSE3tU2Cql3Tu/s8efvcbreTIqIEQQzA1ILI4XAY5ggcLmJcLhccDu3uUjgcNv7Ot3E6nUntIxNkOTcLCEVRc7bvVAiEZPz7nb149q098AaikQS7TcL08bVoGVuDercDdW4HaqvsqK6wxS2AB0NRVbT3BHGgw4f9nT4c6PRjd6sH+zq0vx/o9OM/7+0f8DqbRYSiMigpRKKGwl1hw8SmKkwc5cbkMTWYN73JNHOfDipj2PF5D974sBWbPmpDIBRdxAgCMLHZjSljazCyxok6twN1bjvqqhxwOYa/DDDG4AlE0NkbREdvEB29ARzo8GPXgT7s7/Chqy+Err62rH0WiySiptKGmko7qvU/ayptqHLZUOWyRv90WuGwW0yVfpkPGGPo84Wxr8OHfe0+7OvwotsThj8YgS8oG38O912xSAJqKu1orq/AqBEujB5RidEjK9BY64TTbiFRmgG8hkhg0pDXFEVRIbCoqYLHF0afP4xebxh9+t8Zg5Z2LGo3EkRBgMUiwCqJsEgiLBYRVU4rRo2oMG4cZYIvFASgWYarCqAiN9dEXl8VjISL9rpLEERpYGpB1NTUhLa2+EUW/3djYyNkWTYeGzduXNw2U6ZMSWofxEC8gQhe2LQHL2zaC39Im+MR1Q4snNqAmYfU49Ax1Rn96EqiiKY6F5rqXJiLkXHvu3NfLz7e24NP9vaiyxOCPygbYwgn+MG0WUQ47Ra4HBbtT7sFDrsFLrsEh80Ch0370x+S0dkbQEdvEJ19QXR7QujzhbH5k05s/qTT2N+4xkpMH1+H6RNqcejYGtitUtqfMx9EZBU79/Xi/U878da2g+jqi0Y96912zJ48AjMm1GHquBq4HOm7RQmCALfLBrfLhonN7rjnAiEZu1s92HWgDz3esBEJ1MSrdswEHnLS/2B6zZKqFy6pENDWrQmrPl8YsqLqwis4/NgAOO0W4zyorrBh0uhqtIypxiGjq01/DJPB4w/j0/19+n+92H3QG3eTYjgskgiHTYJFErS6MV0sywoz5vn9TzvjXmO1iKiusKG6wgZ3hQ02q6QtxkVoEcAEYkkQBdgtEmxWEXabBLtVi0ZVuqyockbFbC5q0cyEoipQmXbuD2eqEAzL2P6ZFinv8wdx4bpX0n5fSRQwakQFxjVUYmxjFSaNcmNCcxUkMbX5jnBDhRz2IAKic8N7HhEEQRQKUwuihQsX4v7774eiKJAkbVHz5ptvYuLEiaivr0dVVRUqKyuxYcMGQxD19fVh69atWL16dVL7IDQYY9i5rxevbTmAt7a1IRTRFkzN9S6cctQEHD6tIeUf1VSpdFoxZ/IIzJkcX9elqgx+PRXOIgqwWSVYLSKsFjHtyEA4ouDzNi927e/DrtY+7DrgwcEuPz4/6MXnB7145q3PYZEEHDKqGi1jq9EypgaTRlfDaS/sVyYiK9jX4cOOz3vw4Wfd+GhPN8KRqFB02i1YOHUkFs1owqFja/ISOXHaLZg6vhZTx9em9XqLRURtbQW6u32QZRWyoqLHE0KPN4web0j/L4xebwh9/gi8gTA8/gg8gQhCYQUMMM6Pzj5gD4APdmkpfZIoYHxTFQ5pdqN5RAVG1bvQPKICblduF3qZoqgqPt7Tq6WqftqJtu7AgG0EAA21ToweWYnRIyowosaBCoeWYupyWLW0OLsEm1UacANDVbVUurCsIgIB2z/twOcHvdjX7sW+Dh88/ggicvKiNFWcdglVusB2V2hCyWm3wGmT4LBb4LRZ4K6wYXxjZcHrCtMhokbd4hL1IVIZw5sftmLDtjZs+bgDssULx2EAE7Tvst0mGWK0yqVF3llM2rHCmP5dYYgo2nemuy8Ef0jGnjYv9rR5gQ+0OlqnXcLUcbWYPqEO08bXYmSNc1hBGkrQg0hLwVQRimipyhFFhd0qodJpgdWS3k0HbqoQUczjrkcQRHliakG0atUq3H777bj88suxZs0abNmyBXfddReuuuoqAFrt0OrVq3H99dejrq4Oo0ePxnXXXYempiaccMIJSe2jnJEVFV19QWz6qB2vbjmAg13ROpNxDZU45agJmDdlZMHTkURRQKXTikpn9vph2KwSJo+uxuTR1QB0x0CLhDfe24f3P+3E1s+60NUXwo49PdixpwfAbggCMK6hCuObqtBU50JjnRNNdS6MrHEiFFG09BZfGL2+MPwhGaIgGHfSeT2NAERrdRJNKwMUVVt48D99wegip7XTr0VVYqiusGH6hDrMPXQEDptcn/bixCxYJBEjapwYUTN8oX9EVuAPKfAHI1otWVBGe08AO/b2YseeHnR7QkZkJZZKpxU1lXZdPFhQ4bCiymXFYZNH4NAx1QVJFfP4w9i5rxfvftyB9z7uGBABaqpzYdIoNw4Z5caEZjdGj6iALc3olygKcDmscOtitLnGEZeyFI4o6NXPZS11K4SIwuJqAVWVJaw1C0dUhCKK8Z8/KMPj10SsNxCBojIEQgoCoUBCodef6kobxjdWYVxjFcY2VKK53oXGWpepo0xyjCCyxAgixhg2f9KJR/7zKfa2e43H62ud8AOQJOCWHy+Dw5b6TzNjDJ19Qew56MXnbV7sbvXg47098AVlvPtxB979uMPY1mYVtWuqQ0s5ZTFRXVVlCNjagFFAT5+Mi258FRFFRVh3EE2EzSKiwmmF22XD+KZKHDKqGoc0uzFqRMWQadQ8QkR9iAiCKDSmFkT19fW4/fbbcc0112DlypUYOXIkLr30UqxcudLY5qKLLoIsy7jiiisQDAaxcOFC3HHHHbBarUnvwyy0dwew/pVd8Pq0tCeeniIIAsAABhb3g8SL0sENDPrBzQz4j5zCGAIhGZ19QXT2BtHjDcXtz26VsGDqSCydPapgi8JCUlvlwKKZTVg4tQGMMbR1B/CRLoh27OlBR28Quw96sPugp6DjrHRaMaG5CjMm1GHGhDqMHllRdseKY7VIqLZod9NjOWbeGG2B2BvEjr092NPmxYFOP/Z3+NDRG4Q3EEmYcvb0hs/RVOfC0sOacdTM5gH7zRb+YAR723347EAfPj3Qh10H+tDeEx+JqXBYMOfQEZh36Ei0jKtBRQYpj6lis0oYWePEyCREaSowpkV7+3yaQOI1Mh6/ZogSDMuaWArL6OwNorXLj15vGFu8ndgSk9oqCMDIGidG1VdgTEMFxjVUYVxTFUZWO0zxXeALfIsgQdSbrn70eTfW/+dT7NSNZFx2C05bNgmHHVILbv8GcwAANgBJREFUp0vBz19/FiqUtFM8BUHQDGOqnZjboqUiqyrD7oMebP2sC1s/68bHe3shK5opTVckFJdiG4tY7YMdgCKL8Cf4nlgkAVaLiGBYE0lhWUXYE0K3J4TdBz14ZfMBAFqka9IoN2ZMqMP0CXUY21gZ91tFKXMEQZgFgSVqOkIMi6Ko6OrKrivOo69+iide/yyr+xwOiyRgQrMbS2c1Y8HUhoKnhBWK/mlbiejqC2Lnvl7s7/ChtcuP1i4/DnYFjPRCp90Ct8sKd4UNFQ6rdteVAaqqRXtUrcmPVp6s188kWrpJkghJFLRiaUnQLMpHVGBsg2ZTXlNpM8WiL1skM/fZJBRW0Nrlh8evRfK4CUFrpx+bPmo3jqckCpg6rgbuCltMPZoEq0WKc9HjPbaMI6L/xaijUhhkVYXXr4mgve1edHsSL0Sb6lyYNqEWC1o0EZTrNNV8z32qhMIK9rRr0Y7dBz3Y3+HDgU5fnGFILE67BROaqnDCwrGYPam+YN+TNn87rnrzOjgkO86o+x7+895+QwjZLCKOXTAGpy6eiLGjatDd7UNfwIefvvq/AICblv8akpibKK/KGIIhGd6AZrrhDWhClEezJUk7p3f5d+CZg49ijHMsvnHot2CVtFRlu1WrD+PnpbY/xTDx6OgNYtcBrc5t1wGP8V3iVLmsWk3j+FpMGVuDt3tex5OfPY8lo47AWVPz0yi9rq6CXOYIghhAea5+TcoJC8eivsaFnr4AZEWFqvIGp0wrSo+pS+cOxjx9qn8aFcciisbCjdff1Fc7UO92oN5tR1WFreApccVCnduBw/v122GMwRuIGAtlwvzYbRLGN1UlfO5rx8vYuL0Nr27ej0/29+HDz7pzNo46tx3jGjSXw0NGuTGxqSoj44tSxG6LT20FtO9cjzeMA50+7O/w4fM2Lz4/6MG+dh8CIRnbdndj2+5uTBlbgzNXTB5gApJrGGPY16lFkYNBhjue3AZAE9jLDhuFUxdPQE1lfLNTS4wAkpkCCbm5loiClio53HnmO2ADDgJVTidGjxi8P5C2Py3tdASA8U1VmD8lGp3a3+HD9s+78eGuLmz/vAcefwRvbj2IN7ceBABUjNsHNAG723uxzdGFhloXat3matpNEER5QILIRFRX2rFqxaGmvVtLDEQQBFSZvECfSB6n3YJlh43CssNGYV+7Fzv39SIQUhAMywiGtT8jsgpVr/ViehSIB9pjb0uIgnbHXevLJMJp1yJ9o0dWYszIChI/aSIIAmqr7KitsmP6hDrjcVlRsb/Dhw1bD+L5TXvx0Z4erL17Ew6f1oCTjhgPp10y6vl4rzQI8XV98e+j/cnvNTHj5pOWIcBbAMiKioNdfnzW6sHuVg8+a/XAJ7bDMQNQVRH1bgeOnjMKS2c3D2oQIQlRAaSoMiAV9prCTRXsGYxDFAWMaajEmIZKHLdgLGRFxSf7evHhZ13Y8XkPPj3gQTDIYAPw2cFuXPf6ewC0GsKGWicmNFXhrOMOzWuqKEEQ5QsJIoIgiASMHlmJ0SMrCz0MIkkskohxuvnCinlj8Nirn+K/H7TirW1teGtb9npkJTUWtyae6ipcWHvBomH7s/E6I0CLEBUaXtNjzaLttkUSMWVcLaaM09woI7KCf20X8ELbNrgrJUh1LnT0BAxhu7/Dh8WzmjEtTfdKgiCIVCBBZCIYY+g46EVXl7coIkSVbgecrsLdvWOMobvDD0XJfK4sFhFBnwyPJ1AUc59N3DVO2JNozmpGerr8iIQLv4DMNxWVdrgqizMy6e0LIuDPvavYaQvG4vBD6vHvd/bi84PeaA0fY1BVzaQmXXj0j0ecql02NI9wYdSISoyqd8EvteHhndvgdtWgs82bcB/9rzkV/hooTEVHqwehAh9ab0cEDp8bkseB9tbcmcjUCRVw+NwYU1WDs06bAZUx9PrC6OoLwmKzYOq4mpy9N0EQRCxkqpAmuTBV2LJxL15/8ZOs7jOXWKwivn7BEXDlyIlrON546RO8t2FvQd67lHC4rFj93SNgLVAD03QL+7dtPoCXn96Rw5GZF1EU8D/nLUR1bWYucPk2VWjd14tH/++9nL8PURqc8Y25aByV3RowMlUgCCIRxXlbuESpb6hA3QgXQiEFyODuZT4I+COQIyraD3gwfnJhGtzu36O5NjmcFkgZ9yTR7vSq2m3kjMdWLPi9YQT9EfR0+jFyEKMBs8KPv80uwWorH0OLYECGIqs4uK8vY0GUbw7ox8xiFYs2KpkMYSUCf8QPi2hBpW0wU4L4a05vqA+MMVTZqnLuLjgcgUgQISUEh8UBhyV3jXEjqgxf2AdJlFBli09PdbpsqCjSKChBEMVH6f4iFSHjJ9VjzoJxRWGq8OyjH+LTjzrQ0+XHeBRGEPV2aU0dT/2fwzCiMbNaD7PbD+eKR//vXbTu60Nvd6DoBFGv3tTz6BNbMHlaQ4FHkz9efnoHtm0+gJ4kmpqaDX7MDjt8LA5fOqGwg8khbx7YhP/b9i9Mr5uCb8z5dsJt+l9zfv7aWvSFPfj5wh9hTNWoPI84nv/b9iC2HNiE0w85CSdMWJSz99nZswvr3vkzGpwjcOGiS3P2PgRBEMNBcWMiLWrqXQCAnq7CLMqCgQhCQa0bfLHdJTcTfO56i3hxXW7Hv7pO+7x9RXzMakr8mEVU7dpkFZO/58id5hQTmCpEFK3GyyrltkbUZjRmzX1NGUEQxFCQICLSorZOF0Sd/oK8f1+PtrByVdrKKl0q23Ax0dcdLPBIUiMUlBHUC/PLThDVFLOI1c4zd4kfM1kXRJYUBBHvRWQGQZQN2+1k4IIrQoKIIIgCQ4KISIuaem1B091VGEHEF1Z8cUikh7tII0RcEDtdVtjs5ZX5W12rNQcutmMmRxT4PCEApS9i04mwSLp4ktXCC6KwLohsORZERoRIIUFEEERhIUFEpEWNHiEK+KKpa/mkXNOlso2RMtdTXIvrcj7+bv0mQCgoIxgonoVkX492E8Nml+BwlraI5REPq5i8ILLwlDkzCCJ9/LYUxp8OsREiMrwlCKKQkCAi0sJmtxh9UHoKECXiC2K3frecSA8ebfB7w0XVzyd6/MtPEFltkuG+1VdEQjZWxArC0I1Ki520aoj0lDmZ5f8GU3/yFSGKFYx8zgiCIAoBCSIibWr04u5CGCuUc4Qgm9gdVuNufTGlYJX78edCsFCmJulQTses2CNEoTynzAFUR0QQRGEhQUSkTU0BjRXKaXGVa4qxjqjcj3/UDIOOmRlJL0Kk1xCZwFQhrObHVEESJYiCtgwhQUQQRCEhQUSkjSGI8pwyV84OY7mAWyAXU/oVd8Ur1+MftUsvHnfAckpzTMtlzkQRIiNlTsx9Y9SosUI45+9FEAQxGCSIiLThTnP5TtspZ4exXFBsEaJIWIHfpy2eqsu0hqwYzTD6yipClHrKnCRqP8eFriFijBmub7Yc9yECYo0VqIaIIIjCQYKISJtavTlrb5cfqpo/h6BySr3JB8XWnJWP0+G0wO7I/YLNjBTbMVNkFZ6+8rDcBmIEkZRKY1Zt20JHiGRVBoN2Pc91DRFA1tsEQZgDEkRE2lS6HZAkAYrC4O3LX+pOOaXe5INiS7+i4w+4a7TIWNBfGNv7VOnr1c4tq02C01X6Ijai8BqiFEwVDJe5wgqikBpNXcu17TYAWHXRFVEpZY4giMJBgohIG1EUUK3XEXXn0ViBL4hrynhBnE24IPJ5QohECl+/MBx0/DXbe2eFtlgthtqvXr3OsBwst4Fo+lcqNUSSSWqIeFNZiyAZVuC5xKbPEUWICIIoJCSIiIwohPU2RQiyi91hMWqxePNMM0PHX6OY0uZ6y8wEQ07DZY5HiJRCR4jyZLnN4VG0MLnMEQRRQEgQERlRCOvtcncYyzaCIBSVjXM5FecPRXVNEQminvJqpJyWqYJeQyQXOELELbfzJYj4+0QoQkQQRAEhQURkRE19fq23yWEsN1TXFd/iuuwFUREdM0PE1pTHMUurMatJIkT5dJgDonNEfYgIgigkJIiIjMh3yhw5jOWGar1I3+yL60hEgc/DBXF5LK4Ho7hS5spLxKbVmFWvIZILbD8dymMPIiAqvChljiCIQkKCiMgInjLn94YRDuX+h5zqR3JDsSyueY2TzW6B3VHePaiiaY7mrvtSFBWe3vJKc+XRjpQas5okQhQpUA0RpcwRBFFISBARGWF3WOCq0H4485E2Rw5juaFYBFGvHomsqSsPt7KhcOvpZ35ffm5GpIunNwjGAItVhKsyP4vsQsMjRKmknZmlhohHiOxkqkAQRBlBgojIGCNtrjP3i2mKEOUGPp/evhBkWS3waAYnWpxPx9/usMDh5Nbb5o0S9cbUD5WLiJXTsN02IkQFN1XQa4jy0IMIiIpGihARBFFISBARGZNPYwVyGMsNTpcVVpu2IPOYuK9NtDifDDWAqLGImSN75XYTQ1EVqEy7qZCSy5zRmLWw0b5woVLmKEJEEEQBIUFEZEw+jRXIYSw3xFpvF8Pimo6/RjEcs3KzyY9d2Kdmu22SCFGeBRFPzesO9ebl/QiCIBJBgojIGB4h6s5xLyJyGMst0cV1EaRf0fEHUByCqNyOWSTGJY6nwSWDhbvMFdp2W82v7fa0uhYAwIed29Ed7MnLexIEQfSHBBGRMdxprrc7AMZYzt6HHMZyi7G4NmnKnCyr8PaFAJRP+tVwuIugoW5UEJVHmqNRPyRIEIXkf2Ilk9QQGaYKebLdHlM1Ci01k6AyFf/Z+9+8vCdBEER/SBARGVNV7YAoCVBkFZ7eUM7ehxzGcoshiPLUUypV+nShZrNLcLqoBxVg/giRqrIYy21XgUeTH6KW26mdo2aJEHHbbWueUuYA4JixSwAAr+3fYAgygiCIfEKCiMgYUYzWn8QaK0TCCnZ8eBB+X3Z+4MhhLLe4TV6gbxTnl5Fb2XDw753PG0YkXNiFdCI8vUGoKoNkEVFRVV6W21YptSi2pDvSKSZpzJov220AmDliGkY46xGQA9hwYFPe3pcgCIJDgojICjxtrkevI9r/eQ8evHMTXnxiO/5532aEgpn/yJPDWG6pNqy3g1AU81lvk8PgQBxOq5E+2mfCVMeoiHWUjYjlEaJUDBWA2Mashf3uhVVuqpC/KKwoiDhmjBYlemnva4ZLH0EQRL4gQURkhZp6bZHacdCL117YiX/et9mo+enp9OPFJ7ZlXF9UbsXZ+cZVYYPFKoIxGGlOZqK3zNzKksXMZhjlKGIjih4hSqEHERDrMldo223ehyi/Eb0jmxfAaXGgzd+BrZ0f5fW9CYIgykYQqaqKm266CUuXLsWcOXNw3nnnYc+ePYUeVslQq0eIPvrgIN7ftA8AMO2wJpz6P7MhWUTs/qQLb736WUbvQYIotwiCgOoa89ak0PFPjNvEZhjleMyiNUSpCSKLaI4aonzbbnMcFjuOaj4cAPDSntfy+t4EQRBlI4huueUW3HfffVi7di3uv/9+qKqKNWvWIBymAs5swK23AaCiyoaTz5yF5SdNwZgJtVh+omar+s5/P8cn29vT2j85jOWH6jrzCyJ3mbiVJUu1iZ3mylMQaREeW4opc5LAa4jM4TKXz5Q5ztFjFkOAgO3dH2Of90De358giPKlLLyLw+Ew7rzzTlxyySVYvnw5AGDdunVYunQpnnvuOZxyyimFHWAMaigANegBk6PpZQzJpZoJKFyO/ogaAZNaamG3MiyYZYEtsh2h93rAgn0Yb3Ni1uQavL8T+Pe/tsHtUjCioTKl/fd26g5jNhEOMQQWzK6QVS0CFL8KNeiLm/tkMI5PDi3H84W7UrtH0tPeCzXgzst7qhYRik2GGvBDlRPXDiiKCm+flhLmdipQA305G4/ArZJ5zYvJa1+qq/Rj1ukFC6fWC4wpItQgwEJ+sBzUjfXqJivuKjHlsWUGP3ai/tf8HcNIRDtPLYIEJg9+nWIQocpWMDkMJquQ9LoZWZWHfF2uMSJETMz7OOqsFZgzYjre7fgQL33+KlZPPzOv708QRPkisFw2jjEJW7ZswVe+8hU888wzmDhxovH4WWedhZaWFlx11VUp71NRVPT1ZfeO7IEPnsYLW59AxNzrr7RgTEBw7xKo/iYIFj+kitTu/jHZCcU3CqK9G84JL+RolESkZyLCBxdAsHohuQ4WejgGjFmg9I0HBBmuQx81u0bJK0qgDsHPjwXEMCxV5koDlnsnAhDhPORJiNZ8CqLC0WG14BOXDS2+EL51oDfp1+23WXDTuDpYVYZ5nsJF+96pciIiCrjo8y6MCue/nmm3w4I/j6mDhTFcM+cC1DQemtX9u91OSFLZJMcQBJEkZREham1tBQA0NzfHPd7Q0GA8lyqiKKC2tiLjscXyeKQVr9WUbq8OqXILDvmwCvZQBeTeSWnto7PSh33VpTtHhcYphTDpIMAilZB7U4vi5QO/y4MPSvg7kg5ShYKpe1QIqi3t71UuUaQINtYDEMrruFWmGHGr0LePiAI2FPgaJzCW8vizxbigjLHBCPY4rOhANyZm+XeWIAgiEWUhiAIBnm4VXyRqt9vR25v8HbxYVJWhry+7dzxXzDoTNR3vwuP3g6lFGrgb5ta9PA7w7pKRTt2wIAFjxzdgnuv4NAc3xL5FAXa7FaFQJM25F+L+KFYYA7xuGbIvfx9EAGCxSJBlZdjk0NFjKzGj+oTcDYYZ/yuqFEh/pYJQV+oLWEEAJEmEoqg5+7jOBobJI4/Lzc4HhSF6MuX/OEqChCMaD0ONo3rQbURJhLvKiT5PAKqiogbA+e0fYr+vLW/jHIzRFY0Yd8z0gr3/d4O92N77GQ5pWIDubl9W900RIoIgElEWgsjh0Iqww+Gw8XcACIVCcDrTL/aVB6l3SJdKSwVOn/YFdHf7sr5vUzG10AMYiMUiora2ovTnPhkm5PftaO6zwMThN0kEzX1uGeq+jyCJEO1OML9q9B6a3TgPs/MztGEppLVDtasBR7gaoCqACjovCYLIPWVxm4SnyrW1xd95a2trQ2NjYyGGRBAEQRAEQRCECSgLQTR16lRUVlZiw4YNxmN9fX3YunUrFi5cWMCREQRBEARBEARRSMoiZc5ms2H16tW4/vrrUVdXh9GjR+O6665DU1MTTjghh/UIBEEQBEEQBEGYmrIQRABw0UUXQZZlXHHFFQgGg1i4cCHuuOMOWK35bz5HEARBEARBEIQ5KIs+RLlAUVR0dWXX/YYKnAsHzX3hoLkvHDT3hYPmvjDU1VWQyxxBEAOgqwJBEARBEARBEGULCSKCIAiCIAiCIMoWEkQEQRAEQRAEQZQtJIgIgiAIgiAIgihbSBARBEEQBEEQBFG2kCAiCIIgCIIgCKJsIUFEEARBEARBEETZQoKIIAiCIAiCIIiyhRqzpgljDKqa/amTJBGKQk36CgHNfeGguS8cNPeFg+Y+/4iiAEEQCj0MgiBMBgkigiAIgiAIgiDKFkqZIwiCIAiCIAiibCFBRBAEQRAEQRBE2UKCiCAIgiAIgiCIsoUEEUEQBEEQBEEQZQsJIoIgCIIgCIIgyhYSRARBEARBEARBlC0kiAiCIAiCIAiCKFtIEBEEQRAEQRAEUbaQICIIgiAIgiAIomwhQUQQBEEQBEEQRNlCgoggCIIgCIIgiLKFBBFBEARBEARBEGULCSKCIAiCIAiCIMoWUwkiWZbx5S9/GR988EFS27/zzjs4++yzMX/+fCxduhSXX345enp6jOdVVcVNN92EpUuXYs6cOTjvvPOwZ8+euH089dRTOPXUUzF79mwcd9xx+Otf/wrGWEr7GI6zzz4bU6ZMSfjfb3/725T2xZkyZQoeeeQR49/btm3D6tWrMWfOHKxYsQL33HPPoK+99dZbcfbZZ8c9lszcx77nYHPPx3HYYYdhwYIFmD9/fty8xc7nzJkzMW/ePMyaNcuY++effx7f+973AJT+3Kdyvk+ZMgXr1q0b8nx/4YUXsGTJEkydOhVTp07Fsccei507dxrPh0IhfOtb38L06dMxZcoUzJ07FzfddJNxvt99991Yu3ZtTuZ85syZWL58OX71q18hEAiktL/+PPLII5gyZUrcY/feey+OPfZYzJ49G1/72tewdevWhK8NhUI47bTT8NBDD6V0rVm3bh2mTJmS9LXm9NNPx7Jly+L28dRTT+Hkk0/G9OnTMW3aNMyaNQvnn3++Mb+qquLMM88c8J1Jlccffxxnnnkm5syZg7lz52LVqlW4//77U95PfzKd91NPPRXHHntsStf3E088EVOmTEn6+n733XdjxYoVxjb8+j5z5kzMnj0bs2bNwpIlS4x9qaqKG2+8ETNmzMDs2bNTnvPvf//7+MpXvjLg8TPPPBNTpkzBW2+9Fff4448/jqlTp6KzszPp94gl29f9dN4zEcONQ5Zl3HjjjTjmmGMwd+5cfP3rX8d7771nPP/CCy8Y132CIIhCYCpBdMcdd2Dy5MmYOXPmsNvu2rUL3/72tzFlyhQ8+OCDWLduHbZs2YIf/vCHxja33HIL7rvvPqxduxb3338/VFXFmjVrEA6HAQCvvvoqLrnkEpx55pl48skncemll+KWW26Ju5gPt49kOemkk/Daa68N+O/CCy9MaT+J6O7uxrnnnotx48Zh/fr1uPDCC3H99ddj/fr1A7a999578Yc//GHA49mY+wsvvNAYx6pVq6AoCoLBINasWWPM280334z77rsP//M//wNFUdDY2IiRI0fixz/+MW655Rbs378fHo8HTzzxRMnPfSpzDgB33nnnoOf7pk2b8P3vfx9erxdXXXUVrrjiCrS1teGrX/2qMV/f/e538frrr+PrX/86/vjHP6Kurg5//vOfjfP961//Ov71r3/hnnvuyfqcP/nkkzjvvPPw4IMPpi1EB+PRRx/F7373O/zwhz/EI488gjFjxuDcc89FV1dX3HYejwff+9738NFHH+HVV19N6Xy/8847ASCpa82PfvQjfPTRR+jo6BhwrVEUBc3NzbjooosgiiI++eQTfPe734Wqqrjllluwe/duSJKEG264Ia25f/jhh/G///u/OPPMM/Hoo49i/fr1+NKXvoSrr74af/zjH5PeTzKkOu87duxAQ0NDSteYpqYmAEjq+t7e3o5f//rXhsDnc37sscdCkiQceeSRkCQJJ554orGvW265Bf/4xz9w0UUXobGxEbIspzTnixYtwrZt2xAMBo3Henp68P7776O5uRmvvvpq3PabNm3C1KlTUV9fn9T+hyIb1/1skMw4/vznP+Ohhx7C2rVr8dhjj2HixIlYs2YN2traAADHHXeccd0nCIIoCMwk9PX1sXnz5rEdO3Yktf0NN9zATjjhBKaqqvHYxo0bWUtLC/v8889ZKBRic+fOZffee6/xfG9vL5s9ezZ74oknGGOMrV+/nq1bty5uv9/73vfYeeedxxhjSe0jGVavXs0uu+yypLdPhpaWFrZ+/XrGGGN/+ctf2JIlS1gkEjGe//3vf89OOOEE49+tra3s/PPPZ3PmzGEnnngiW716tfFcsnPP33OouV+0aBHz+XzGvPFx8HmbNWsWu/fee425j51PPvf//ve/2THHHFPSc5/q+d7S0sKOOuqoQc/3iy++mE2bNi1uvu677z7W0tLCHn30Udba2sqm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345LL70UAFLax3A88cQTmDt3btx/a9asGfZ1b7zxBj7++GP87ne/w4wZMzB37lzjLj8nGAwmHCOAYceZytwDWp3Jl770JYwdOxbf+973UFVVhT/+8Y94+eWXUVtbC4fDETdvsePgd2Vjx+p2u7Fs2TK0tLTEzf3IkSMHbMs/V7HPPWMsrfP9a1/7mjH3PGK3fPnyAee7LMu49NJL8fHHH2POnDkIhUIIBALGOGPP92AwaCzY+D5aWlriCp6zMeezZs3C2rVr8e1vfxs/+clPkt7P3//+d8ybNw/f//73MXHiRHzlK1/BV7/6VeP5VL+jqqoCiEYqgNSuNddccw2efvppbNy4Ed/61rdw4MABtLe3JxwDEH8OeL1evPfee5g6dSouuugiOJ1ObNiwAd/4xjeM48n3MXnyZLz77rspz/2JJ56If/zjHzj22GOxefNm/P73v8dXvvIVnHjiiXj77beT3k82551fY2JJ9fo+ceJEvPPOO1i7dq0hFBK9f6LX9r++n3baaXj55ZexcuXKuH1MmDABVqsVXq83pTnngogxhu3bt6O9vR2LFy+GJElYtGiRUUe0ceNGLFiwwLg+DEWur/upEnvt4dd9bo6RzDh27tyJqqoq/OlPf8IDDzyAM844A5dccgm2bdsW97pDDz007tpDEASRL0whiHp6eiDL8oBC01WrVuHpp59GOBzG7t278e6772LVqlVx20QiEfz85z/HXXfdhbVr1xppGA6HAwAGFMeGQiE4nc64xyorKzF9+nScdNJJ+PnPf46nn34a+/btS2kfw7FixQo89thjcf9dc801w75ux44dqK6ujruTNm3aNGNs/LMmGiMAI3IwGKnMPaAtGjiRSASKouDtt9/G2rVrUVdXh3A4HDdvsePgi9HYsVZWVsLpdGLMmDFxc8/TuEpx7mVZTut8nzBhQtz5XlNTY9z55WPq6urCBRdcgBdffBF//OMf4XK54HQ648YZe743Nzdj7969ced7dXW1kerCP0+6c/7oo4/iqquugtvtxlFHHYULLrggpZS5HTt2YNasWXGPzZ071/h7qt9R7lJWWVkZ93gy1xoAuO2224xrDU99EkUx4RgAxI3BYrEgHA7jrrvuwoUXXohf/vKX6Onpwe7du/Hxxx/H7aOurg4dHR1pzf2cOXOMO/iPPvoofvSjH8Hr9eK8885L2t0sm/POrzH9SWbOFUUBADz22GPG9Z1HdhK9v6IocWnUQPR8P+644zBx4kTs2rULP/7xj41IDd+HJEmoqamBz+dLac4XLVqEnp4efPrpp3jttdcwffp01NXVAdCihtxpbtOmTTjqqKOS2meur/upEnvdBzSRyd9ruHEcOHAAP/nJT/CTn/wExx13HGbNmoVf/epXmDJlCm6++ea41/HzniAIIt+YQhDxHzC+YOaceuqpCIVCeOmll/D4449j9uzZmDRpkvE8/5F/4okncMMNN8TZn/I0CO5iw2lrazPuDm/atMmoleDwVK22trak9pEsFRUVGD9+fNx/yexDEIQB8wIgblHZ1NSUcIwAhn2PVOYeiN6B5XPv9/vxhS98AV/5yleMccTOW+w4+F3ltra2uLnn8xk793zBWspzn+r5Lsty3PleUVFhOGrxOT/77LPx3nvv4Y477sDRRx9tzFdTUxO6u7sHRAn8fr8xZr4Pj8djLPL5c+nO+YQJE3DaaafhxhtvxMMPP4yrr746pf0kOgZWq9X4e6rf0XSvNXyB9+STTw641vBoZv8xcBdFQLvW2Gw2NDY2orq6GkD0WlNZWWksKPk+FEWBKIopzX1rayuuuuoqI91LFEVMnz4d3/3ud3HXXXfB5/MlXRuTzXnvL1A4yVzf//a3vwHAgDmPfb9YfD6fcY2Kvcbw6xW/sbNw4cKEn0FRFHi93pTO98bGRkycOBHvvvsuXn/99bgaoSVLlqCtrQ0ffvghtm/fbtSnDkeurz2pkijyxq89w41j8+bNiEQiAwT2YYcdht27d8c9lkjQEgRB5ANTCKLa2lpYrdYBdq1utxvHH388nn/+eTz77LM444wzjOfC4TDOP/98bNmyBXfccQdOOumkuNdOnToVlZWV2LBhg/FYX18ftm7dioULFwIA7rnnHlx77bVxr9u8eTMsFgsmTJiQ1D5yzbRp0+DxeIw7yADw2Wefwev1Gv9euHAh3n77beNuKqAV0k+cOHFYe9dM537EiBGYPHly3DgOPfRQY974OKxWK3bv3g273Y4NGzYYcx87n7Fzb7PZIAhCSc691WpNec4B4K677hr0fG9uboYgCGhvb8e9996LhQsXxs3X/PnzoaoqfvnLXxqv2bVrFzo7OyFJUtz5vnPnTqMGIFtzfuSRR+Lcc8/FP/7xD7zyyitJv27q1Klx9RkA4vrY1NfXY+LEiXHniSzL2LRpU8Ix19bWAtAWzrEMd77fddddAJBw7g855JAB14lQKIRIJBJ3rdm5cyf2799vLBY3b94MSZLg8Xgwf/78uH10dXWhpqYmpbm32Wx46KGH4tLQYj8fAIwYMSKpfWVz3vk1JtGYhrvG7N27FwAGzDmgie7+14f29nYjfYtfY2KvV9/85jcHvb4rioKenh60tbWlfL4fddRReOedd/Duu+/GiZ7Ro0djwoQJuPfee1FXVzegj9Ng5Pq6n02GGwevL/roo4/iXrdjx44Bkaeuri7j2kMQBJFPTCGIAGD27Nn48MMPBzy+atUqPP/88/j8889x8sknG4/feuutRqrWIYccgvb2duO/cDgMm82G1atX4/rrr8eLL76I7du34+KLL0ZTUxNOOOEEAMA555yDLVu2YN26ddi9ezeefvppXHfddfjGN76B2trapPahKAra29vj+lCkwnCvP+KII3DYYYfh0ksvxXvvvYf3338fl156adwd/FWrVsHr9eLyyy/Hzp078cgjj+Cuu+7C+eefn9QYZs+ejQ8++GDAOJKZe4vFAp/Ph/b2dixfvhwejwdXXXUVvvjFL+Laa6/FHXfcgdNOO82Yt2984xu4/vrrMXPmTGzevBlnnHEG6uvrwRiLm/vt27dj8uTJJTv3sed77DgGm3MA2L17d9z5rigKfD4fwuEwfv/730MQBDDGsHXrVrzxxhu48MILMXLkSBx77LFobGzEUUcdhZ07d+KnP/0pnn32WaxZswYWiwXf/OY34873zZs3o6qqKutz/sMf/hATJkzAlVdeaQgSfu4Mxre+9S1s374dv/3tb7Fr1y48/vjj+Pvf/z5gm7/97W949NFHsXPnTvy///f/EAwG8eUvf3nQ/cY6pvFxHHvssYOe7/xOduy1hqffJbpOPPPMM5AkKe5as3fvXlRVVeH888/Hbbfdht/85jcYMWIEDjnkEBx//PHGPl544QV8+OGHeP/991Oa+7q6OqxZswY33ngj1q1bh23btmHPnj146aWX8P3vfx9HHHEEFixYUJB55xHm/px88sl47rnnBr3G8Dqf2Os7T787/fTTB1wfeAoun/MtW7bg3HPPxaZNm7Bq1So8/PDD+PKXvwxZltHb24uzzjrL2MczzzwDVVXR2NiY8vm+aNEiPP300xAEAfPmzYt7bunSpXj66aexaNEiI/phhut+Kp9vKIYbx+zZszF//nxcdtllePPNN/HZZ5/hD3/4A9544w185zvfidvXhx9+mJEbHkEQRNoU0vM7ljvuuIOdcsopAx5XVZUdffTRcf1TGNN6YLS0tCT8780332SMMSbLMvvd737HjjzySDZnzhx23nnnsT179sTt55VXXmFnnHEGmz17Nlu+fDn7y1/+whRFMZ4fbh979uwZtk/DUH1Zknl9V1cX+/GPf8zmzp3LFi1axO666y521FFHxb1m8+bN7Mwzz2QzZ85kxxxzDPu///u/Qfd32WWXxfWjuOOOO9gXvvCFAePoP/f8+aHm/r777mNnnnkmmzFjBps3bx6bM2dO3LzFzuesWbPY/Pnz2axZs+LmPhwOs8MPP5w99dRTJTv3sed77DgGO98Hm++Wlhb23//+l82aNWvQ5/mc+Xw+9u1vf5tNnTqVtbS0sMMOO4ytW7cu7nxva2tjLS0tbMGCBTmZ8w0bNrApU6YYvXJuuummuN42ifjvf//LVq5cyWbOnMlWrlzJbrvttgGvuf3229myZcvY7Nmz2de+9jW2devWQffX0tLCli5dGvcYH0eq1xo+v/2vE8cff/yA93jllVfYaaedxqZOncqmTJnCZsyYwS688ELW2trKGIteaxYsWMBaWlrYN7/5zZTnnjHGHn30UXbWWWex+fPnsxkzZrDjjz+e3XDDDczn8w34vEORzXm/4447Eo79xhtvZC0tLSnN+d/+9jfW0tLCPvvsswHXh6uvvpodc8wxxn5eeeUVNnPmzCG/O3wfM2fOZHPnzk1rznt7e9nUqVPZ+eefP+C5l156yegHlsp+c33dT3YciZ4/5phj2E033ZT0OHp6etiVV17Jli9fzubOncu++tWvsg0bNsRtw6/7zzzzzKBjIQiCyBWmEUTd3d1s7ty5bMuWLXGPe71eNmfOHPb6668XaGTD89e//pU9+eSTBXt9pvC5X7t2bdw4CjX3Tz/9NFuxYgULh8PDblusc9//fOfjKPT5fvvtt7OzzjpryG2yPWcrV67M2r6SYbBrzWmnnWaKa81VV13FfvKTnyR8Lptzn895H+r6PnXq1ILPOWOMnXLKKezBBx8c8HiurhGFvu6bbRypXPcJgiCyjWlS5mpqavCtb33LyNXv7e3Fs88+i8svvxyjR4+OawBoJrxeL5566qm0x5fp67NBTU0NVq9ejccffxyLFi0q+Nzffffd+P73v5+w7iCWYp772PPd6/XiiSeeQCAQKOj5Hg6H8Y9//AM//OEPB90m23P2r3/9K+8pMomuNddeey38fn/BrzXd3d145plncOGFFw54Lptzn+95H+z6fu6556Kqqqrg1/fXX38d4XAYX/rSl+Iez9U1wgzXfTONA0j+uk8QBJETCq3IYgmFQmzlypVs8+bNrLOzk82fP58df/zx7MMPPyz00IYkFAoV9PXZIBQKsdNPP73gc//cc8+x73znO0lvX8xzH3u+HzhwoODn+9/+9jd21VVXDbtdNuesUPNv1mvN2rVr2e233z7o89mar0LMe6I5P+644wo+54qisDPOOIO9++67CZ/P1VyZ4brPmDnGkep1nyAIItsIjOnemQRBEARBEARBEGWGaVLmCIIgCIIgCIIg8g0JIoIgCIIgCIIgyhYSRARBEARBEARBlC0kiAiCIAiCIAiCKFtIEBEEQRAEQRAEUbaQICIIoqT42c9+hhUrVgz6/IoVK/Czn/0sjyMiCIIgCMLMkCAiCIIgCIIgCKJsIUFEEARBEARBEETZQoKIIIiyRVEU3HvvvTj11FMxe/ZsLF++HNdffz1CoZCxzdlnn42zzz477nUbNmzAlClTsGHDBgDAI488gunTp+Ohhx7C4sWLcfjhh2Pnzp15/SwEQRAEQaSHpdADIAiCyAWyLA+7zS9/+Uv885//xHnnnYcFCxZg69at+NOf/oRt27bh9ttvhyAISb+foii48847cc0116C7uxuTJk3KZPgEQRAEQeQJEkQEQZQc+/btw4wZM4bcZufOnXj44Yfxk5/8BN/5zncAAIsXL0ZDQwMuvfRSvPLKKzj66KNTet8LLrgAy5cvT3fYBEEQBEEUABJEBEGUHCNHjsSf//znhM9997vfBQC89dZbAICTTz457vmTTz4ZP//5z7Fhw4aUBdG0adPSGC1BEARBEIWEBBFBECWHzWbDrFmzBn0OAHp7ewFo4ikWi8WC2tpaeDyelN/X5XKl/BqCIAiCIAoLmSoQBFGWVFdXAwDa29vjHo9EIuju7kZtba3xmKIocdv4/f7cD5AgCIIgiLxAgoggiLLk8MMPBwA8+eSTcY8/+eSTUBQF8+fPBwBUVlaitbU1bpu33347P4MkCIIgCCLnUMocQRBlyeTJk7Fy5UrcdNNNCAQCWLhwIbZt24Y//vGPOOKII7B06VIAwDHHHIN///vf+PWvf40VK1Zg06ZNeOyxxwo7eIIgCIIgsgYJIoIgypZrrrkG48ePx/r16/HXv/4VDQ0N+MY3voHvfe97EEUtgL5q1Sp8/vnnePTRR3H//fdj4cKFuOmmm3DWWWcVePQEQRAEQWQDgTHGCj0IgiAIgiAIgiCIQkA1RARBEARBEARBlC0kiAiCIAiCIAiCKFtIEBEEQRAEQRAEUbaQICIIgiAIgiAIomwhQUQQBEEQBEEQRNlCgoggCIIgCIIgiLKFBBFBEARBEARBEGULCSKCIAiCIAiCIMoWEkQEQRAEQRAEQZQtJIgIgiAIgiAIgihbSBARBEEQBEEQBFG2/H9DPTT9wb83KgAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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t7MnnniC7dy5k02YMIFdeOGF4vmNGzey9vZ29q1vfUs89oMf/IAdcsghWc+JlXRz/vOf/5zNmjUrr/0nLswXLVrE/ud//kf8OxqNsqOPPprddttt4rGXX36ZLViwgC1evJi1t7ezqVOnZnWtOeqoo+LeM9m15q677mKXXXYZO/jgg9kJJ5zAJkyYEHetufjii9mECRPY+vXrGWPGteb0009nCxYsYJ999pm41lx33XXskksuyWluFi9ezJYtWzbo8euvv97ReT/55JNZe3s7u/XWW229F7/GPProo+I9U13f+/r62GWXXcYmT57MJkyYwI444ggx3hUrVsRdr/g1hu/r+uuvF9eYxYsXs0ceeSSrOdmwYQNrb29nb731lnjs6aefZnPmzGE333zzoODnK1/5Cvvtb3+b1XtYKeR1P5f3TIadcZx88snsN7/5jfh3X18fa29vZ88//7x4jF/3VVXNeowEQRD54hrJ3EMPPYS2tjYcdNBBAIBrr70Wxx13XNw2fX19mDZtGl599VWcfPLJ+O1vfwtJksTz/O+enh6sX78eAwMDmD17tni+oaEBkydPxurVqwEAp556Kn76058CMOQX//rXv7B69WrMmTNHvObjjz/G+PHji3LMdtm5cyd+8IMfYMaMGZg/fz6eeuqpuOfXrFmDww8/HB6PRzx25JFHYvPmzdizZw8A4MMPP4TX68WTTz6JQw45JO71duceAP7v//4Pb775JrZt24b58+fj9ttvBxCb+0mTJmHDhg1i7vk4IpEIDjjgAITDYcyePVvMfUNDAyZNmoSnnnpKzP3cuXPR19eHV199tWLnPtvzHQDmzJmDM888E1OnTsW8efPw5JNPAjDO9/nz50PTtLjzvba2FgDw5ptvYu3atZAkCb/5zW8AGOf7jh07IEkSGhsbxWsURUEoFML777+f79Qlxe/3x82VHV588UWcdNJJmDp1Kk4//XRs375dPLd3715s3rw57rg9Hg8OO+ww8T0HDEnOf/zHfwjp2LBhw7K61nBZ1OOPP47jjjsO3/3udwEYnz+/1uy///7YsWMHHnnkEXz5y1+G1+uNu9a0tbWhvb0dBx10kLjWLFq0CK+88grGjRsnrjVf/epX8cwzz2DXrl1ZzRMAyLKMd955Bz09PXGPn3POOXjooYey2lch5/2rX/0qAKC1tRVA9tf3xx9/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27x5M/r7+8W/Z82ahbVr14q7qYBRSD927NhBWYhE8p374cOHi7ng4zjooIPE3PNxeL1ebNmyBX6/H6tWrRJzb/1MEuc+GAxW5Nx7vd6s5xwA7rnnnpTn+6hRoyBJEnbv3o37778fs2bNipvbQw89FLqu41e/+pV4zaZNm7B3714oihJ3vn/88ceiBgAozJwfeeSROPPMM/GXv/wlq7qYiRMnxtVn8PFwWlpaMHbs2LjzRFVVrFmzRnzPrTQ1NQEwFs5WMp3v99xzDwAknftx48YNutaEw2FEo9G4a82GDRuwfft2sVh87733oCgK+vr64PP54q41nZ2dGDlyZFZz7/P58Mgjj8TJ0KzHBwDDhw+3ta9Czju/xiQbU6ZrzLZt2wBg0JwDRjCTeH3fvXu3kG/xa4z1evXd73435fVd0zT09PRg7969WZ/vRx11FN5++2288847cUHPPvvsgzFjxuD+++9Hc3PzoD5OqSj2db+QZBoHry/6+OOP4173ySefDMo88fOeIAii1LgiIAKAadOm4cMPPxz0+JIlS/Diiy/i888/xwknnCAev/3224VUa9y4cdi9e7f4LxKJwOfzYenSpVi+fDlefvllrF+/HhdeeCHa2tqwaNEiAMD3vvc9vP/++1ixYgW2bNmCZ599Ftdffz2+853voKmpCePHj8e4cePw61//GmvWrMFnn32G3/zmN3j33Xfxgx/8AIDxI7p7926EQqGcjjvT64844ggccsghuPTSS/Huu+/i3//+Ny699NK4O/hLlixBf38/Lr/8cmzYsAGPP/447rnnHpx77rm2xjBt2jR88MEHg8ZhZ+49Hg8GBgawe/duLFiwAH19fbjqqqvw1a9+Fddeey1WrlyJk08+Wcz9d77zHSxfvhxTpkzBe++9h1NPPRUtLS1gjMXN/Y4dOzBs2LCKnXvr+W4dR6o5BwzDA+v5rmkaBgYGEIlEcMMNN0CSJDDGsG7dOrzxxhs4//zzMWLECBx77LFobW3FUUcdhQ0bNuCSSy7B888/j7POOgsejwff/e534873t956C8OHDy/4nP/kJz/BmDFjcOWVV4qAhJ87qfj+97+P9evX47e//S02bdqEJ598Evfdd9+gbe6++2488cQT2LBhA/7rv/4LoVAIX//611Pu1+qYxsdx7LHHpjzf+Z1s67WGy++SXWuee+45KIoSd63Ztm0b6uvrce655+KOO+7Addddh+HDh2PcuHH41re+Ja41b731Fj788ENs27Ytq7lvbm7GWWedhZtuugkrVqzARx99hK1bt+KVV17Bj370IxxxxBE47LDDHJl3nmFO5IQTTsALL7yQ8hqzePFiAIi7vnP53SmnnDLo+s4luHzO33//fZx55plYs2YNlixZgkcffRRf//rXoaoqGhoaMHbsWHGNeemll6BpGj7//POsz/fZs2fj2WefhSRJmDlzZtxz8+bNw7PPPovZs2eL7IcbrvvZHF86Mo1j2rRpOPTQQ3HZZZfhzTffxObNm/G73/0Ob7zxBs4555y4fX344Yd5ueERBEHkjJOe31ZWrlzJTjzxxEGP67rOjj766Lj+KYwZPTDa29uT/vfmm28yxhhTVZX9z//8DzvyyCPZ9OnT2dlnn822bt0at5/XXnuNnXrqqWzatGlswYIF7LbbbmOaponnd+/ezX7+85+zOXPmsKlTp7JvfetbbPXq1eL5rVu3ZuzTkK4vi53Xd3Z2sp/97GdsxowZbPbs2eyee+5hRx11VNxr3nvvPfbNb36TTZkyhR1zzDHsf//3f1Pu77LLLovrR7Fy5Ur25S9/edA4EueeP59u7h944AH2zW9+kx188MFs5syZbPr06XFzb/1Mpk6dyg499FA2derUuLmPRCLs8MMPZw8//HDFzr31fLeOI9X5nmq+29vb2b/+9S82derUlM/zc35gYID953/+J5s4cSJrb29nhxxyCFuxYkXc+f7pp5+y9vZ2dvjhhxdlzletWsUmTJggeuXcfPPNcb1tkvGvf/2LLV68mE2ZMoUtXryY3XHHHYNec+edd7L58+ezadOmsdNPP52tW7cu5f7a29vZvHnz4h7j48j2WsPnN/Fa86UvfWnQe7z22mvs5JNPZhMnTmQTJkxgBx98MDv//PPZzp07GWOxa83hhx/O2tvb2ZIlS7Kee8YYe+KJJ9hpp53GDj30UHbwwQezL33pS+zGG29kAwMDg443HYWc95UrVyYd+0033cTa29uzmvO7776btbe3s82bNw+6vl999dXsmGOOEft57bXXRFPdZP89//zz4hozefJkNm3atJzmvKenh02cOJGde+65g5575ZVXRD+wbPZb7Ou+3XEke/6YY45hN998s+1xdHd3syuvvJItWLCAzZgxg33rW99iq1atituGX/efe+65lGMhCIIoFq4JiLq6utiMGTPY+++/H/d4f38/mz59OvvnP//p0Mgy86c//Yk9/fTTjr0+X/jcL1u2LG4cTs39s88+yxYuXMgikUjGbct17hPPdz4Op8/3O++8k5122mlptyn0nC1evLhg+7JDqmvNySef7IprzVVXXcUuuuiipM8Vcu5LOe/pru8TJ050fM4ZY+zEE09kDz/88KDHi3WNcPq677ZxZHPdJwiCKDSukcw1Njbi+9//vtDq9/T04Pnnn8fll1+OffbZJ64BoJvo7+/HM888k/P48n19IWhsbMTSpUvx5JNPYvbs2Y7P/b333osf/ehHSesOrJTz3FvP9/7+fjz11FMIBoOOnu+RSAR/+ctf8JOf/CTlNoWes//3//5fySUyya411157LQKBgOPXmq6uLjz33HM4//zzBz1XyLkv9bynur6feeaZqK+vd/z6/s9//hORSARf+9rX4h4v1jXCDdd9N40DsH/dJwiCKApOR2RWwuEwW7x4MXvvvffY3r172aGHHsq+9KUvsQ8//NDpoaUlHA47+vpCEA6H2SmnnOL43L/wwgvsnHPOsb19Oc+99XzfsWOH4+f73Xffza666qqM2xVyzpyaf7dea5YtW8buvPPOlM8Xar6cmPdkc37cccc5PueaprFTTz2VvfPOO0mfL9ZcueG6z5g7xpHtdZ8gCKLQSIyZ3pkEQRAEQRAEQRBDDNdI5giCIAiCIAiCIEoNBUQEQRAEQRAEQQxZKCAiCIIgCIIgCGLIQgERQRAEQRAEQRBDFgqICIIgCIIgCIIYslBARBBERfHzn/8cCxcuTPn8woUL8fOf/7yEIyIIgiAIws1QQEQQBEEQBEEQxJCFAiKCIAiCIAiCIIYsFBARBDFk0TQN999/P0466SRMmzYNCxYswPLlyxEOh8U2Z5xxBs4444y4161atQoTJkzAqlWrAACPP/44Jk+ejEceeQRz5szB4Ycfjg0bNpT0WAiCIAiCyA2P0wMgCIIoBqqqZtzmV7/6Ff72t7/h7LPPxmGHHYZ169bhD3/4Az766CPceeedkCTJ9vtpmoa77roL11xzDbq6ujB+/Ph8hk8QBEEQRImggIggiIrjiy++wMEHH5x2mw0bNuDRRx/FRRddhHPOOQcAMGfOHIwcORKXXnopXnvtNRx99NFZve95552HBQsW5DpsgiAIgiAcgAIigiAqjhEjRuCPf/xj0ud+8IMfAADeeustAMAJJ5wQ9/wJJ5yAX/ziF1i1alXWAdGkSZNyGC1BEARBEE5CARFBEBWHz+fD1KlTUz4HAD09PQCM4MmKx+NBU1MT+vr6sn7fmpqarF9DEARBEISzkKkCQRBDkmHDhgEAdu/eHfd4NBpFV1cXmpqaxGOapsVtEwgEij9AgiAIgiBKAgVEBEEMSQ4//HAAwNNPPx33+NNPPw1N03DooYcCAOrq6rBz5864bdauXVuaQRIEQRAEUXRIMkcQxJDkwAMPxOLFi3HzzTcjGAxi1qxZ+Oijj/D73/8eRxxxBObNmwcAOOaYY/D3v/8dv/nNb7Bw4UKsWbMGf/3rX50dPEEQBEEQBYMCIoIghizXXHMNDjjgADz22GP405/+hJEjR+I73/kOfvjDH0KWjQT6kiVL8Pnnn+OJJ57Agw8+iFmzZuHmm2/Gaaed5vDoCYIgCIIoBBJjjDk9CIIgCIIgCIIgCCegGiKCIAiCIAiCIIYsFBARBEEQBEEQBDFkoYCIIAiCIAiCIIghCwVEBEEQBEEQBEEMWSggIgiCIAiCIAhiyEIBEUEQBEEQBEEQQxYKiAiCIAiCIAiCGLJQQEQQBEEQBEEQxJCFAiKCIAiCIAiCIIYsFBARBEEQBEEQBDFkoYCIIAiCIAiCIIghy/8H5rcXD9OGCvMAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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N96IPfbYA9OmTXPc5+eccw5OPPHErOUnnXQSJk+ejDfffNO0/IknnsCUKVOwfft2279hxOv3vpvftKJQO2RZxo033oiDDjoIM2bMwH/913/hnXfe0dcb3/sEQRCVwFcG0bJlyzBx4kTsueeeBbf94osv8JOf/ASTJ0/Ggw8+iBtuuAHvvfcefvGLX+jb3HrrrbjvvvuwZMkS3H///VBVFaeddhoSiUTW8V544QU89NBDWcudHCMfRxxxBF599dWs/5199tmOjmNFZ2cnTj31VIwdOxYrVqzA2WefjaVLl2LFihVZ295777344x//mLXci74/++yz9XYsWrQIiqIgFovhtNNO0/vt5ptvzurPk08+We/7Qw45BL29vXjyySdrvu+d9DkA3HXXXTnv99WrV+Occ85BX18fLr/8clx66aXYsmUL/uM//kPvr8suuwyvvvoqbr75Zpx99tnYuHEjOjo69OP/13/9F/7xj3/gb3/7m+d9/tRTT+H000/Hgw8+6NoQzcWjjz6K//mf/8EvfvELPPLII9hxxx1x6qmnms4NAHp7e/Gzn/0MH3/8MV555RVH9/tdd90FALbeNb/85S/x8ccfY9u2bVn99vOf/xwvvfQSEokERo4cid7eXpx11llQVRW33norNmzYgEAggOuvv95V3z/88MP43e9+h5NOOgmPPvooVqxYgeOPPx5XXnklbrnlFtvHsYPTfv/kk08watQoR++YtrY2ALD1ft+6dSuuvvpqMMayjvXDH/4QW7duxciRI03HuvXWW/H3v/8d5557LlpbWyHLsqM+nz17Nj766CPEYjF9WVdXF95//32MHj0ar7zyimn71atXY8qUKRg+fLit4+fDi/e+F9hpx5///Gc89NBDWLJkCR577DGMHz8ep512GrZs2QLA/N4nCIKoCMwn9PT0sJkzZ7JPPvnE1vbXX389O+yww5iqqvqyVatWsUmTJrGvvvqKxeNxNmPGDHbvvffq67u7u9m0adPYk08+aTrW5s2b2X777ccWL17MDjroIH25k2PkY/HixezXv/617e3tMGnSJLZixQrGGGO33XYbmzt3Lksmk/r66667jh122GH63+3t7eyMM85g06dPZ4cffjhbvHixvs5u3/PfzNf3s2fPZtFoVO833g7eb1OnTjX152effcYmTZrEjjjiCL3vX3rpJXbQQQfVdN87vd8nTZrE9t9//5z3+3nnncd22203U3/dd999bNKkSezRRx9l7e3tbMqUKezf//63fr9/73vfY5MmTWJvvfUWY0y73/fcc092yCGH6Mfwus8vvvhiNmvWLNvHsmLFihVs0qRJ+t+HHXYY+5//+R/972QyyQ488EB222236ctefPFFNn/+fLZw4UI2adIkNnXqVEfvmv3339/0m1bvmrvuuov9+te/ZnvssQc76qij2OTJk0399sYbb7BJkyaxWbNm6e+aTz/9lM2fP5+tW7dOv9+vueYaduGFF7rq+4ULF7IlS5ZkLb/22msr2u/HHnssmzRpErv11ltt/RZ/xzz88MP6b+Z6v/f29rJf//rXbPfdd2eTJ09m++67r+lYS5YsYVOmTDG93/mxpk+frj8zCxcuZH/7298c9fn69evZpEmT2Jtvvqkve+qpp9icOXPYTTfdxI477jjT9kcccQT7wx/+YOvYVnj53nfzm1bYacexxx7Lrr76av3v3t5eNmnSJPbss8/qy1566SW2YMECJsuy4zYSBEEUi288RA888ADa2tqw6667AgB+//vf45BDDjFt09vbi2nTpuHf//43jj32WPzhD3+AIAj6ev7v7u5urFu3DtFoFLNnz9bXNzc3Y/fdd8eqVav0ZYwxXHzxxTjuuOOwzz77mH7P7jFKTXt7O8466yzMmDEDBxxwQNYs2urVq7HPPvtAkiR92X777Ycvv/wS27ZtAwB8+OGHCAaDeOKJJ/Cd73zHtL/dvgeA//3f/8Ubb7yBr7/+GgcccABuv/12AOm+32233bB+/Xq933g7EokEdt55Z8Tjcb0/GWO48sorMWrUKEQiEf235s6di66urprue6f3OwDMmTMHp556KqZOnYp58+bhiSeeAKDd7wcccAAURTH1V0NDAwDgjTfewJo1awAA++67r36/H3DAARBFUe/PdevWIZFI4Ouvv8Z7770HwPs+D4fDpr6yw/PPP49jjjkGU6dOxfe//318++23+rrt27fjyy+/NJ23JEnYe++9TW1+4YUX8J//+Z966NiQIUMcvWt4WNQjjzyCQw45BD/84Q8BaNefvyfGjh2LTZs24aGHHsJ3v/tdBINBUxteeeUV1NfX44QTTtDfNRMnTsS//vUvxONx/X4/8sgj8c9//hMDAwOO+14URbz99tvo7u42Lf/pT3+K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/B2TiZ0+5xMljz32mP5+554dq99XFEU38jPf74qioLOzU79+3FPDjxEIBDB06FBEo1FHfT579mx0dXXh888/x6uvvordd98dw4YNA6B5DbnS3OrVq7H//vvbOmap3/tOMb73AS2Ulv9WoXZs2rQJ559/Ps4//3wccsghmDp1Kq644gpMnjwZN998s2k/ft8TBEGUG18YRNxzwAfMnGOOOQbxeBz/+te/8MQTT2DatGmYMGGCvp5/5J988klcf/31JvlTHgbBVWw4W7ZsQWtrK9599118+umnuOWWW/RZ7Ntvvx3ffvstZsyYgdWrVxc8hhMaGhqw8847m/5n5xiCIGT1CwDToLKtrc2yjQAK/oaTvgfSM7C87/v7+/Hd734XJ554ot4OY78Z28FnlV9++WVT3z/33HP46quvTH3PB6y13PdO73dZlk33e0NDg66oxfv8lFNOwTvvvINly5bhwAMP1PsrFotBUZSs+z2ZTOL+++833e+9vb36IJ+fj9s+HzduHI499ljceOONePjhh3HllVc6Oo7VNQgGg/q/nT6jbt81fID31FNPZb1ruDczsw2KopjeNV999RUSiQTmz5+vv2sOPfRQNDQ06ANKfgxFUSCKoqO+b29vx+WXX66He4miiN133x1nnXWWHjpmNzfGy3435nkasfN+/+tf/woAWX1u/D0j0WgUgUAg6/0+ffp03Hbbbejv74ckSRg/frzlOSiKgr6+Pkf3e2trK8aPH4+3334br732milHaO7cudiyZQs+/PBDrFu3DnPmzLF1zFK/e5xi5bXj755C7Xj33XeRTCazDOzvfOc72LBhg2kZN2gJgiDKjS8MopaWFgSDwSy51ubmZhx66KF4/vnn8eyzz+KEE07Q1yUSCZxxxhl47733sGzZMhxxxBGmfadMmYLGxkasXLlSX9bT04O1a9di1qxZmDZtGp577jk8/vjjutfgP//zPzFq1Cg89thj2HPPPQseoxzstttu6O3t1WeQAeDLL7805dzMmjULa9asMYWdvfHGGxg/fnxBeddi+37EiBGYOHGiqR277rqr3m+8HcFgEBs2bEA4HNYTZx9//HHcc889kCQJ+++/v6nvQ6EQBEGoyb4PBoOO+xzQ8iFy3e+jR4+GIAjYunUr7r33XsyaNcvUX8cffzwATXqb3+/8GEuXLjXd7+vXr9dzALzq8/322w+nnnoq/v73v+Pll1+2vd+UKVNM+RkATHVshg8fjvHjx5vuE1mWsXr1ass2t7S0ANAGzkYK3e/Lly8HAMu+32WXXbLeE/F4HMlk0vSuOf/88yGKIpYtW6a/a5YtW4be3l7stddepmN0dHRg6NChjvo+FArhoYceMoWhGc8PAEaMGGHrWF72O3/HWLWp0Dvm66+/BoCsPgc0ozvz/bB161aEQiHT+/2hhx7ChAkTEAgE0NLSgn/84x+W73dFUdDV1YUtW7Y4vt/3339/vPXWW3j77bdNRs8OO+yAcePG4d5778WwYcOy6jjlotTvfS8p1A6eX/Txxx+b9vvkk0+yPE8dHR36u4cgCKKc+MIgAoBp06bhww8/zFq+aNEiPP/88/jqq69w1FFH6ctvv/12PVRrl112wdatW/X/JRIJhEIhLF68GEuXLsWLL76IdevW4bzzzkNbWxsOO+wwRCKRLK/BkCFDIEkSdt55Z0QikYLHALSP6NatW011KJxQaP99990X3/nOd3DRRRfhnXfewfvvv4+LLrrINIO/aNEi9PX14ZJLLsH69evxyCOPYPny5TjjjDNstWHatGn44IMPstphp+8lSUI0GsXWrVsxf/589Pb24vLLL8eRRx6J3//+91i2bBmOPfZYvd9+8IMf4MYbb8T69esxMDCA66+/HmPGjMHUqVNNfb9u3TpMnDixZvveeL8b25GrzwFgw4YNpvtdURREo1EkEglcd911EAQBjDGsXbsWr7/+Os4++2yMHDkSBx98MMaOHYujjz4aN998M9rb29Hd3Y3/+7//QygUwuGHH26639999100NTV53ue/+MUvMG7cOFx22WW6QcLvnVz8+Mc/xrp16/CHP/wBX3zxBZ544gncc889Wdv89a9/xaOPPor169fj//2//4dYLIbvfe97OY9rVEzj7Tj44INz3u98Jtv4ruHhd1bviWeeeQaBQMD0rjnllFMwfvx4XHvttYjH41BVFddffz122WUXHHroofoxXnjhBXz44Yd4//33HfX9sGHDcNppp+HGG2/EDTfcgI8++ggbN27Ev/71L5xzzjnYd999sffee1ek37mHOZOjjjpK9xBbvWN4no/x/c7D74477ris90NjYyPq6upM7/enn34aH374IRYsWIBwOIz6+nr09vaiu7sbJ598sn6MZ555BqqqorW11fH9Pnv2bDz99NMQBAEzZ840rZs3bx6efvppzJ49W/d++OG97+T88lGoHdOmTcNee+2FX//613jjjTfw5Zdf4o9//CNef/11/PSnPzUd68MPPyxKDY8gCMItvjGIDjnkENNsH2f27NloaWnJih3/xz/+AcYYfvWrX+kSp/x/fGbz3HPPxfe+9z1ceumlOPnkkxEIBLBs2TLL2cpcFDrGpk2bMHfuXF2FzSmF9hdFEbfffjt22WUX/PjHP8YZZ5yBo446So9RB7TZ2jvvvBNffPEFFi5ciFtuuQUXXXSRPpgoxCGHHKKHehjbYafv29vb8de//hVz587FMcccg1/96lf44osv8Oijj0IURYRCIV2BbtmyZTjvvPMs+9MYkpFMJvH222/j7LPPrtm+N97vxnbk6nMAWfc77/s1a9bgn//8J1RVRV9fHy6++GL86Ec/wptvvomNGzfqMflLlizB7Nmzcc455+AnP/kJWlpaTOcCAIsXL4aqqnjttdc87/NwOIwlS5bg22+/xQ033ABAKzabT4Z4t912w1/+8hesXLkSxx57LJYvX44zzzzTtM1JJ52Ec889F3/84x+xaNEifPPNN/jrX/+adW5GPvvsM9Pfd911F84777y89zsA03vm3HPP1bfJfE+Ioojhw4eb3jWhUAjLly/HmDFj8Oijj2Lbtm1oaWnB8uXLEQqF9GP85je/QTQaxciRIx33/S9/+UtcddVVWLVqFU455RQcccQRuPrqq7H//vvjtttuM51vOfs9U2Kb88EHHyAej+fscy6Tbux37jX50Y9+lPV+OPbYY7NCrvixnnvuObS3t5uONWfOHP0YF198MRoaGnD33Xc7vt/33XdfxGIx7Lvvvlnfl7lz56K/v9/kOfLDe9/J+eWjUDtEUcSf//xn7LfffvjNb36DE044AW+88QaWL19uMn74e//ggw923RaCIAjXlL/0kTWdnZ1sxowZ7L333jMt7+vrY9OnT2evvfZahVpWmL/85S/sqaeeqtj+xcL7fsmSJaZ2VKrvn376abZgwQKWSCQKblutfZ95v/N2VPp+v/POO9nJJ5+cdxuv+2zhwoWeHcsOud41xx57rC/eNZdffjk7//zzLdd52ffl7Pd87/cpU6ZUvM8ZY+zoo49mDz74YNbyUr0jKv3e91s7nLz3CYIgvMY3HqKhQ4fixz/+sR6r393djWeffRaXXHIJdthhB1MBQD/R19enz+xXYn8vGDp0KBYvXownnngCs2fPrnjf33333TjnnHMKevKque+N93tfXx+efPJJDAwMVPR+TyQS+Pvf/45f/OIXObfxus/+8Y9/lD1Exupd8/vf/x79/f0Vf9d0dnbimWeewdlnn521zsu+L3e/53q/n3rqqWhqaqr4+/21115DIpHQc+04pXpH+OG976d2APbf+wRBECWh0haZkXg8zhYuXMjeffddtn37drbXXnuxQw89lH344YeVblpe4vF4Rff3gng8zo477riK9/1zzz3HfvrTn9revpr73ni/b9q0qeL3+1//+ld2+eWXF9zOyz6rVP/79V2zZMkSduedd+Zc71V/VaLfrfr8kEMOqXifK4rCTjjhBPb2229bri9VX/nhvc+YP9rh9L1PEAThNQJjqeB4giAIgiAIgiCIQYZvQuYIgiAIgiAIgiDKDRlEBEEQBEEQBEEMWsggIgiCIAiCIAhi0EIGEUEQBEEQBEEQgxYyiAiCIAiCIAiCGLSQQUQQRE1x8cUXY8GCBTnXL1iwABdffHEZW0QQBEEQhJ8hg4ggCIIgCIIgiEELGUQEQRAEQRAEQQxayCAiCGLQoigK7r33XhxzzDGYNm0a5s+fj6VLlyIej+vbnHLKKTjllFNM+61cuRKTJ0/GypUrAQCPPPIIdt99dzz00EOYM2cO9tlnH6xfv76s50IQBEEQhDukSjeAIAiiFMiyXHCb//7v/8bjjz+O008/HXvvvTfWrl2LP/3pT/joo49w5513QhAE27+nKAruuusuXHXVVejs7MSECROKaT5BEARBEGWCDCKCIGqOb775BnvssUfebdavX4+HH34Y559/Pn76058CAObMmYNRo0bhoosuwssvv4wDDzzQ0e+eeeaZmD9/vttmEwRBEARRAcggIgii5hg5ciT+/Oc/W64766yzAABvvvkmAOCoo44yrT/qqKPwm9/8BitXrnRsEO22224uWksQBEEQRCUhg4ggiJojFAph6tSpOdcBQHd3NwDNeDIiSRJaWlrQ29vr+Hfr6+sd70MQBEEQRGUhUQWCIAYlQ4YMAQBs3brVtDyZTKKzsxMtLS36MkVRTNv09/eXvoEEQRAEQZQFMogIghiU7LPPPgCAp556yrT8qaeegqIo2GuvvQAAjY2NaG9vN22zZs2a8jSSIAiCIIiSQyFzBEEMSiZOnIiFCxfipptuwsDAAGbNmoWPPvoIt9xyC/bdd1/MmzcPAHDQQQfhpZdewtVXX40FCxZg9erVeOyxxyrbeIIgCIIgPIMMIoIgBi1XXXUVdt55Z6xYsQJ/+ctfMGrUKPzgBz/Az372M4ii5kBftGgRvvrqKzz66KO4//77MWvWLNx00004+eSTK9x6giAIgiC8QGCMsUo3giAIgiAIgiAIohJQDhFBEARBEARBEIMWMogIgiAIgiAIghi0kEFEEARBEARBEMSghQwigiAIgiAIgiAGLWQQEQRBEARBEAQxaCGDiCAIgiAIgiCIQQsZRARBEARBEARBDFrIICIIgiAIgiAIYtBCBhFBEARBEARBEIMWMogIgiAIgiAIghi0kEFEEARBEARBEMSg5f8D6UrJJJIy0oQAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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tWsTHhsKhXD66afjhRdesDXW3HXXXRg9erTlseaMM87A7Nmzu52no6MDf/rTnzBhwgSMGTMGl112mT4mZeN5B4DFixfje9/7HiZNmoTJkydj/vz5ePbZZ22dIxGZ9vtpp52GY4891tb4fuKJJ2L06NGWx/cnn3yy2xiunUv7bRjPlWmfX3HFFTj77LO7bf/e976H0aNH4/PPPzdtX7x4McaMGYPGxkZL548n2+O+k2smIl07JEnC3XffjWOOOQaTJ0/GD3/4Q3zxxRf658ZxnyAIosdhLuLBBx9kv/nNbyztu3nzZjZp0iS2cOFCtnHjRrZs2TJ26qmnsh/96Ef6Pvfeey+bPn06e//999m6devYRRddxI4//ngWCoW6ne+dd95hdXV17JhjjjFt/+CDD9iECRPY3r17WUNDg/4nEAhY/l7nnXce++Uvf2k6XvvT3t5u+TxG6urq2EsvvcQYY6ypqYlNnz6d/e53v2MbN25kL774IpswYQJ78cUXux331FNPsTFjxrDzzjvPtN1K32vXTNb35557rt6OBQsWsEmTJrFx48axe++9V+/7v/3tb93uycyZM019f95557HFixcXfd/bed7r6urYIYcckvR5X7ZsGRs9ejQ79NBD2bPPPsv+7//+jx1yyCFsypQp+vP+29/+lh133HFs2bJl7JFHHtHPqRGJRNisWbPY+PHjs97nW7duZU899RQbP348+9Of/mT5XIl46aWXWF1dnf7vl19+mU2cOJG99tprbMOGDezXv/41mzZtGmtsbDQd19bWxi666CJWV1fHfvGLX9gaaw455BBWV1dnaax54okn2OjRo9nYsWO7jTUXXHABmzVrFqurq2OzZs1i5557LjvllFOYLMv68z5jxgy2cuVKR33/wgsvsEmTJrEXXniBbd68mW3atIn94x//YOPHj2f33nuv5fMkIhv9/oMf/MDStbQx5sc//jGrq6uzNL6fccYZbPTo0WzOnDndzqXdv1mzZpnOpfX5W2+9xU444QS2a9cuW32uPdPG/Zubm9mYMWPY0UcfzW6//XbT/n/4wx/YGWecYencicj2uG/3momw0o577rmHzZw5k3300Uds69at7Prrr2eHHXYY27t3r76PNu4TBEH0NK4xhtra2tiUKVPY+vXrLe1/5513suOPP54piqJvW7ZsGaurq2Pbt29noVCITZ48mT399NP6562trWzixIns9ddfN51r79697IgjjmDnnXdeN2Po4YcfZqeddloG30wd5K1OvKxifEE9+OCDbNasWSwSieif33HHHez444/X/11fX88uvfRSNmnSJHbiiSeaXopW+167Zqq+nzFjBuvs7NT7XmuH1vcTJkww3ZNNmzaxuro6dtJJJ+l9/5///IfNnTuXPfTQQ0Xb93af97q6OnbkkUcmfd6vuuoqNnbsWFPfPvPMM6yuro698sorrL6+no0ZM4Z98MEH+vP+3e9+l9XV1bGVK1fqx1x++eXs0EMPddo1jLHUff7b3/6WTZ06NaPzx0/Kjz/+ePb//t//0/8diUTY0UcfzR588EF923vvvcfmzJnD5s2bx+rq6tiECRNsjTVHHnmk6ZqJxprHH3+c/eY3v2Hjx49np5xyChs9erRprPnss89YXV0dmzp1qj7WbNiwgc2ZM4dt2rRJH2tuvfVW9utf/9pR38ybN48tXLiw2/bbbrstr/1++umns7q6OvbAAw9YupY2xrz44ov6NZON7+3t7ew3v/kNGzduHBs9ejSbPn266VwLFy7UDQFtjNHOddttt+ljzLx589gLL7xgq082btzI6urq2Oeff65ve+ONN9jMmTPZPffc083wOemkk9hf//pXW9cwks1x38k1E2GlHaeffjr7y1/+ov+7vb2d1dXVsbffflvfpo37kiTZbiNBEEQmuCZM7rnnnsPAgQNx8MEHAwBuueUWHHfccaZ92tvbMXHiRHzwwQc4/fTT8de//hUcx+mfa39vbW3FN998g87OTsyYMUP/vLKyEuPGjcOyZcv0bYwx/Pa3v8UZZ5yBadOmdWvXt99+i1GjRmX1u9qlvr4el19+OSZPnozZs2fj9ddfN32+fPlyTJs2DaIo6tuOOOIIbN26Ffv37wcArFmzBh6PB4sXL8ahhx5qOt5q3wPAf//7X3z22WfYuXMnZs+ejYceeghArO/Hjh2LjRs36n2vtSMcDmPYsGEIhUL6PWGM4aabbkL//v3h9/v1a82aNQvt7e344IMPirbv7T7vADBz5kxceOGFmDBhAo466igsXrwYgPq8z549G7Ism573srIyAMBnn32GFStWAACmT5+uP++zZ88Gz/Om34MgCAgGg/jqq68y7rtE+Hw+U19Z4Z133sFpp52GCRMm4Nxzz8Xu3bv1zxobG7F161bT9xZFEYcffrjpe7377rv4wQ9+oIeLVVVV2RprtFCol19+Gccddxx+/OMfA1DvvzbWDB06FHv27MELL7yAE044AR6Px9SGjz76CKWlpTjrrLP0seaggw7C+++/j5EjR+pjzcknn4x///vf2Lt3r61+AgCe57Fq1Sq0traatl9yySV47rnnbJ0rm/1+8sknAwAGDBgAwP74/vLLL+Oqq67Sv8vrr7+ujzE7d+7Enj178OKLL2LgwIEIh8P6ORljWL16NU466STT+K6d1zi+n3LKKXjiiSds9dGoUaMwYMAArFy5Ut/20UcfYdasWZg1axa++eYbfRxoamrCpk2bMGvWLEvnzvW4b4ctW7bgggsu0Mcebdy32o7a2lq8//772LlzJ2RZxnPPPQev14sxY8box2jj/pIlSxy3kyAIwgmuMYbeffddU/7CWWedhR07dmD58uX6tn//+9+orKzEUUcdhVGjRmHSpEmmczzyyCPo168fRo8ejfr6egDAoEGDTPv0799f/wwAFi1ahH379uHqq69O2K7169ejqakJP/zhD3HkkUfinHPOwYcffpjp17WMJEm4+OKL0dzcjKeeegp33303HnvsMdM+9fX1GDhwoGlb//79AQB79uwBAMydOxf33nsvhgwZ0u0aVvseUI2hc845B2+99RbOOecc3Hnnnfj000/xyCOPQBAE1NXVmfre2I7S0lJ9OxDr+0mTJqGjo0O/lsfjwcyZM7Fhw4ai7Xu7zzugTk7PPPNM/Pvf/8Y555yD5557Dn369MHo0aO79W0kEsGiRYtQWVmJ5uZm7N27F9XV1fjnP/9pet4FQTD9HrZt24aysjJceeWVWe1zSZLwwQcf4LXXXsMZZ5xh+biVK1fiF7/4BU444QQsXrwY8+bNw8MPP6x/bvV3fsstt+DSSy+F1+sFANMkzMpYM3ToUADA888/jzvvvBNTpkyBKIq4++679evMnDkTTz75JMaOHQuge9/+97//Bc/zGDx4MJ5++mns2bMHv/rVr3SjRxtrbr31VkiShPPOO89231988cVYu3YtZs+ejUsuuQQPP/wwvvrqK1RUVGDEiBGWz5Ptfn///fdN+9kd359//nkMGTIENTU1qKysxG233aZff8yYMXq/l5WVQZIk/bhFixahs7MTt956q+n62ruivr5eH2MefvhhbNy4ES+++KLlfgKAGTNmYNWqVfq/P/74Y8ycORMTJ05ERUUFPv74YwDAihUr4Pf7cdhhh6U9Z0+M+3Z46qmnTGOPNu5bbcf1118Pj8eDY489FhMmTMBdd92Fe+65R/9dAbFx/7333suorQRBEHZxhTGkKAq+/vpr1NXV6dvGjBmD8ePH66vfAPDKK6/g9NNPhyAI3c7x17/+FR988AFuvPFGeDwePUlbm/xo+Hw+hEIhAMA333yD++67D7fddlu3/QD1hbR582a0trbiF7/4BR5++GFMmjQJl1xyif4isMrrr7+OyZMnm/5cfPHFaY/79NNPsWHDBvy///f/MH78eEyePBl/+ctfTPsEg8GE3xOA/l2TYafvAeCHP/whzjzzTAwZMgQ/+9nPUFFRgfvuuw8ffPABqqur4ff7TX1vbIe2Guv1ek19X1JSAlmWTe0aNWoU2trairLvGWOOnvdzzz1X73vNUzdnzpxuz7skSbjuuuuwYcMGTJo0CaFQCIFAABzHdXveOY7T26k976Iook+fPlnt8wkTJmDhwoX4yU9+gmuuucbyeZ566ilMmTIFV1xxBUaMGIGzzz4b3//+9/XPrfzOjSiKAiDmoQDsjTU333wz3nzzTSxbtgwXXXQR9uzZg3379iVsAwDTWLNp0yYwxrBkyRIcc8wxqKmpQX19PX70ox+hs7PTNNYccsgh8Pl8tvv+xBNPxD//+U8ce+yx+PLLL3HHHXfg7LPPxoknnqh7B62QzX7Xxhgjdsf3ESNGYOXKlVi4cKFuJCS6vvHYZOO79q74wx/+gC1btuh9/sgjj4Dnedxwww22+lwzhhhj+Oabb7Bv3z7MnDkTgiBgxowZ+OijjwAAy5Ytw+GHH66PD6nI9bhvF+PYo437mhCGlXZs3LgRFRUVuP/++/Hcc8/hrLPOwrXXXot169aZjjv44INNwgoEQRA9gSuMoZaWFkiShNraWtP2+fPn480330Q4HMa2bduwatUqzJ8/37RPJBLB7373OyxatAgLFy7UQy+0sCtjyASgDs4lJSUIhUK49tprcfnll5tWiY2IooilS5fi2WefxRFHHIFDDjkEv/nNbzBr1qxuq3TpmDt3Ll599VXTn5tvvjntcevXr0dVVZVpBW3s2LGmsDK/35/wewLQPQbJsNP3ADB8+HB9n0gkAlmWsWLFCixcuBA1NTUIh8Omvje2Q5uItre3m/o+FAp1C53q27cv/H5/Ufa9JEmOnvfhw4ebnvc+ffroK75am5qamnDZZZfhvffew3333YfS0lKUlJRAFEU0Nzd3e94ZYygpKQEQe97POussRCKRrPT5K6+8ggULFqCyshJHHnkkLrvsMlthcuvXr8eECRNM2yZPnqz/Pd3vPB5Njay8vNy03cpYAwAPP/ywPtZo4U48zydsAwDTWDN06FBIkoT7778fgwcPhs/nw3333Yft27fjww8/NI01Q4cOxeDBgx31/aRJk/SV+1deeQW/+tWv0NHRgZ/+9KeWVcyy2e/aGBOPlT7XFkleffVVfXyvrKzUP4+/vizLuoEfP77Lsozm5mb9/p1wwgmmPp84cSJqa2sxfPhwW30+Y8YMtLS0YPPmzfj4448xbtw41NTUAFC9hZqi3PLly3HkkUdaOmeux327GMd9QA05166Vrh179uzBNddcg2uuuQbHHXccJkyYgD//+c8YPXo07r33XtNxNTU1emgdQRBET+EKY0jzGGiTZY3TTjsNoVAI77//PhYvXoyJEyeacki0F/zrr7+OO++80yRxqoVvNDQ0mM7Z0NCAAQMG4Msvv8SGDRtw33336avXDz30EHbv3o3Jkyfr4RtlZWWmFxCgrl7ZjecvKyvDsGHDTH+Mq9PJ4DiuW78AME0oBw4cmPB7Akh7DTt9D8RWXrW+7+rqwgknnICzzz5bb4ex743t0FaTP/zwQ1PfL1myBNu3bzf1vSzL4Hm+qPve7vMuSZLpeS8rKwNjDEDseT///PPxxRdf4LHHHsPRRx+tP+/BYBCyLHd73iORCJ599lnT885xnD7BBzLr8+HDh+P000/H3XffjRdffBE33XSTrfMkugcej0f/e7rfeaLzAfb7XpvcvfHGG93Gmn79+iVsgyzLprFm+/btCIfDmDNnjj7WfOc730FZWRl27txpGmu0599O39fX12PBggV6mBrP8xg3bhwuv/xyPVzMmM+Timz2uzGv04iV8V3L4Ynvc+P1jHR2dkIQhG7j+6RJk/Dggw+iq6sLoijqIYPx47ssy+jXr5+t533AgAEYMWIEVq1ahU8++cSUEzRr1iw0NDRgzZo1+OabbzBz5kxL58z12GOXRN46bexJ144vv/wSkUikm3F96KGHYtu2baZtmjFLEATRk7jCGKqurobH40FTU5Npe2VlJb7zne/gnXfewdtvv42zzjpL/ywcDuPSSy/FV199hcceewwnnXSS6dgxY8agvLwcS5cu1be1tbVh7dq1mDp1KiZOnIglS5bgtdde070FP/jBD9C/f3+8+uqrOOSQQ7BhwwZMmTLFdA4AWL16NQ466KAc9ER3xo4di/b2dmzYsEHftnXrVlOOzdSpU7FixQpTqNlnn32GESNGdPM+xJNp3/ft21fvC60dBx98sN73Wjs8Hg+2bdsGn8+nJ8m+9tpreOqppyCKIo488shufR8IBIqy7z0ej+0+B9T8h2TP+6BBg8BxHPbt24enn34aU6dONT3vZ555JgDgxhtv1J937Ry333676Xn/9ttv9Zh/IDt9fsQRR+DCCy/EP//5T1t5MGPGjDHlY2jt0aitrcWIESNMz4kkSVi+fDmmTp3a7XzV1dUA1EmzkXTP+6JFiwAgYd+PHDmy21gTCoUQiURMY80111wDnufx2GOP6WPNY489hvb2dni9XtNY09TUhP79+9vqe6/XixdeeMEUemb8foDqcbVCNvtdG2MStSndGLNz504A6NbngGrIxI/v+/btg9frNY3vL7zwAkaNGgVBEFBdXY1//etfCcd3WZbR2tqKxsZG28/7kUceiZUrV2LVqlUmg+eAAw7A8OHD8fTTT6OmpqZbnaZk5Hrczybp2qHlE3377bem49avX9/N46Q99wRBED2JK4whAJg4cSLWrFnTbfv8+fPxzjvvYPv27TjllFP07Q899JAenjVy5Ejs27dP/xMOh+H1enHeeefh9ttvx3vvvYdvvvkGV111FQYOHIjjjz8efr+/m7egqqoKoihi2LBh8Pv9GDVqFEaOHIk///nPWL58OTZt2oS//OUv+OKLL3D55ZcDUF+g+/btQzAYdPS90x0/ffp0HHroobjuuuvwxRdf4Ouvv8Z1111nWrmfP38+Ojo6cP3112Pjxo14+eWXsWjRIlx66aWW2jBx4kSsXr26Wzus9L0oiujs7MS+ffswZ84ctLe3Y8GCBTj55JNxyy234LHHHsPpp5+u9/2PfvQj3H333di4cSMCgQDuvPNODB48GBMmTDD1/Z49e1BVVVW0fW983o3tSNbngCpuYHzeZVlGZ2cnwuEw7rjjDnAcB8YY1q5di08//RQ///nP0a9fPxx77LEYOnQoTj31VNx7772or69Ha2sr/ve//8Hr9eLEE080Pe+ff/45+vbtm/U+/+Uvf4nhw4fjxhtv1I0R7dlJxkUXXYRvvvkGf/3rX7FlyxYsXrwYTz31VLd9nnjiCbzyyivYuHEjfv/73yMYDOK73/1u0vMaldG0dhx77LFJn3dtBds41mghd4nGmrfeeguCIJjGmvPPPx8jRozAbbfdhlAoBEVRcOedd2LkyJH4/ve/r481n3/+OdasWYOdO3fa6vuamhpcfPHFuPvuu3HXXXdh3bp12LFjB95//31cccUVmD59Og4//PC89LvmWY7nlFNO0T3DicaYefPmAYBpfNdC7s4444xu43t5eTlKSkpM4/ubb76JNWvWYO7cufD5fCgtLUV7ezsqKysxYsQIfYx59913Icsytm/fbvt5nzFjBt58801wHIcpU6aYPjvqqKPw5ptvYsaMGbrXww3jvp3vl4p07Zg4cSIOO+ww/OY3v8Fnn32GrVu34m9/+xs+/fRTXHLJJaZzrVmzJiPVO4IgCCe4xhg67rjjunkBAPUlU11d3S1W/F//+hcYY7j66qt1GVPtj7aieeWVV+K73/0ubrjhBpxzzjkQBAGPPfZYwlXKRPA8jwcffBATJ07Er371K8ybNw9ffvklnnjiCT35fc+ePZg1a5autmaXdMfzPI+HHnoII0eOxEUXXYRLL70Up5xyih6TDqirtI8++ii2bNmCefPm4b777sN1112nTyTScdxxx+nhHcZ2WOn7+vp6PPHEE5g1axZOO+00XH311diyZQteeeUV8DwPr9erK8099thjuOqqqxLeE2MYRiQSwRdffIFrr722aPve+Lwb25GszwF0e961vl+xYgX+/e9/Q1EUdHR04Le//S0uuOACfP7559ixY4ceg79w4ULMmDEDV1xxBX7yk5+gurra9F14nsett96KcDiMDz74IOt97vP5sHDhQuzevRt33XUXAODxxx9PKTU8duxYPPLII1i6dClOP/10LFq0CJdddplpn+9973u48sor8be//Q3z58/Hrl278MQTT5i+WzybNm0y/fvxxx/HVVddlfJ5B2AaZ6688kp9n/ixhud51NbWmsYar9eLRYsWYfDgwXjllVewf/9+VFdXY9GiRfD7/fpY84tf/AKdnZ1oa2uz3fe/+tWvcPPNN2PZsmU4//zzcdJJJ+Evf/kLjjzySDz44IOm79uT/R4vo62xevVqhEKhpH2uSaEb+13zllxwwQXdxpLTTz+9W5iVdq4lS5agvr5eP8/s2bNx6aWX6mPM1VdfDb/fj0WLFtl+3qdPn45gMIjp06d3e7/MmjULXV1dJo+RG8Z9O98vFenawfM8/v73v+OII47A7373O5x11ln47LPPsGjRIpPhE4lEsGrVKhx77LGO20IQBOGIni9tlJjm5mY2efJk9tVXX5m2d3R0sEmTJrFPPvkkTy1LzyOPPMLeeOONvB2fKVrfL1y40NSOfPX9m2++yebOncvC4XDafQu17+Ofd60d+X7eH330UXbOOeek3CfbfTZv3rysncsKycaa008/3RVjzYIFC9g111yT8LNs9n1P9nuq8X3MmDF573PGGDv11FPZ888/3217rsaIfI/7bmuHnXGfIAgim7jGM9SnTx9cdNFFemx+a2sr3n77bVx//fU44IADTMX93ERHR4e+op+P47NBnz59cN5552Hx4sWYMWNG3vv+ySefxBVXXJHWg1fIfW983js6OvD6668jEAjk9XkPh8P45z//iV/+8pdJ98l2n/3rX//q8bCYRGPNLbfcgq6urryPNc3NzXjrrbfw85//vNtn2ez7nu73ZOP7hRdeiIqKiryP75988gnC4bCeW6eRqzHCDeO+m9oBWB/3CYIgsk6+rTEjoVCIzZs3j3355ZessbGRHXbYYew73/kOW7NmTb6blpJQKJTX47NBKBRiZ5xxRt77fsmSJeySSy6xvH8h973xed+zZ0/en/cnnniCLViwIO1+2eyzfPW/W8eahQsXskcffTTp59nqr3z0e6I+P+644/Le57Iss7POOoutWrUq4ee56is3jPuMuaMddsd9giCIbMIxFg2GJwiCIAiCIAiC6EW4JkyOIAiCIAiCIAiiJyFjiCAIgiAIgiCIXgkZQwRBEARBEARB9ErIGCIIgiAIgiAIoldCxhBBEARBEARBEL0SMoYIgigqfvvb32Lu3LlJP587dy5++9vf9mCLCIIgCIJwK2QMEQRBEARBEATRKyFjiCAIgiAIgiCIXgkZQwRB9FpkWcbTTz+N0047DRMnTsScOXNw++23IxQK6fucf/75OP/8803HLV26FKNHj8bSpUsBAC+//DLGjRuHF154ATNnzsS0adOwcePGHv0uBEEQBEHYR8x3AwiCIHKBJElp9/njH/+I1157DT/96U9x+OGHY+3atbj//vuxbt06PProo+A4zvL1ZFnG448/jptvvhnNzc0YNWpUJs0nCIIgCKIHIGOIIIiiY9euXRg/fnzKfTZu3IgXX3wR11xzDS655BIAwMyZM9G/f39cd911+PDDD3H00Ufbuu5ll12GOXPmOG02QRAEQRA9DBlDBEEUHf369cPf//73hJ9dfvnlAIDPP/8cAHDKKaeYPj/llFPwu9/9DkuXLrVtDI0dO9ZBawmCIAiCyBdkDBEEUXR4vV5MmDAh6WcA0NraCkA1nIyIoojq6mq0t7fbvm5paantYwiCIAiCyB8koEAQRK+kqqoKALBv3z7T9kgkgubmZlRXV+vbZFk27dPV1ZX7BhIEQRAEkXPIGCIIolcybdo0AMAbb7xh2v7GG29AlmUcdthhAIDy8nLU19eb9lmxYkXPNJIgCIIgiJxCYXIEQfRKDjroIMybNw/33HMPAoEApk6dinXr1uG+++7D9OnTcdRRRwEAjjnmGPznP//BX/7yF8ydOxfLly/Hq6++mt/GEwRBEASRFcgYIgii13LzzTdj2LBheOmll/DII4+gf//++NGPfoSf/exn4HnVcT5//nxs374dr7zyCp599llMnToV99xzD84555w8t54gCIIgiEzhGGMs340gCIIgCIIgCILoaShniCAIgiAIgiCIXgkZQwRBEARBEARB9ErIGCIIgiAIgiAIoldCxhBBEARBEARBEL0SMoYIgiAIgiAIguiVkDFEEARBEARBEESvhIwhgiAIgiAIgiB6JWQMEQRBEARBEATRKyFjiCAIgiAIgiCIXgkZQwRBEARBEARB9ErIGCIIgiAIgiAIolfy/wFFtargeiGViwAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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PBUM3XnnnZg6dSoOOuignNtu3rwZX/va1zBt2jQ8+OCDuOmmm/Dee+/hW9/6lrHNrbfeivvuuw+rVq3C/fffD1VVcd555yEejxvbfPTRR7jooovwyiuvGP8efvhhV8dwwkknnWT5G/zfJZdc4uo4dnR0dODcc8/F+PHj8cgjj+CSSy7BDTfcgEceeSRt23vvvRe/+tWv0h4vxthfcsklxnmsWLECiqIgGo3ivPPOM8bt17/+tTGekydPxtixYzF27Fi8+OKLeOWVV/DEE0+gp6cHjz/+eNmPvZsxB4C77ror4/W+du1aXHrppejt7cXVV1+Nq666Cm1tbfjiF79ojNePf/xjbN++Haeffjpuv/12tLS0YO7cucb1/uUvfxn/93//h3vuuafoY/7EE0/g/PPPx4MPPph3EJqJxx57DL/4xS/wrW99C48++ijGjh2Lc889F+3t7Zbtenp68PWvfx0fffQRXn75ZVfX+1133QUAjuaab3/72/joo4+wb9++tLlmzJgxGDduHG699VbcfffdmDZtGi6++GKoqopbb70VW7duhSRJuPHGG/Ma+4cffhj/+7//izPPPBOPPfYYHnnkEZxxxhn4yU9+gt/85jeOj+MEt+O+ceNGNDY2uppjmpubAcDR/L5371787Gc/A2PM2Oajjz7Cl770JYTDYXz+85/HX/7yF/z2t781jnXrrbfir3/9K775zW+iqakJsiy7GvNFixZh/fr1iEajxmOdnZ14//33MXr0aLz88suW7deuXYvp06djxIgRjo6fjWLM+8XAyXn87ne/w0MPPYRVq1bhb3/7GyZNmoTzzjsPbW1tAIDjjjvOmPcJgiAGHOYRuru72fz589nGjRsdbX/jjTeyE044gamqajz2xhtvsJaWFrZt2zYWi8XYvHnz2L333ms839XVxebMmcMef/xxxhhjqqqyuXPnsmeffdb2bzg5hhNWrlzJvve97zne3gktLS3skUceYYwx9vvf/54deeSRLJFIGM//8pe/ZCeccILxe2trK7vwwgvZ3Llz2YknnshWrlxpPOd07PnfzDb2ixYtYpFIxBg3fh583GbPns3uvfdeY+z/9re/pY3nP/7xD3bMMceU9di7vd5bWlrYEUcckfF6/853vsNmzJhhGa/77ruPtbS0sMcee4y1trayadOmsdmzZxvX+6effspaWlrYW2+9xRjTrveDDjqIHXfcccYxij3m3//+99mCBQscH8uORx55hLW0tBi/n3DCCewXv/iF8XsikWBHH300+/3vf2889sILL7ClS5ey5cuXs5aWFjZ79mxXc80RRxxh+Zt2c81dd93Fvve977FZs2axU045hU2bNs0y18yePZu1tLSwDRs2GMf5+OOP2dKlS9mGDRuM6/26665jl19+eV5jv3z5crZq1aq0x6+//vpBHffTTjuNtbS0sFtvvdXR3+JzzMMPP2z8zUzze09PD/ve977HZs6cyaZNm8YOP/xwxlhyfv/GN76Rcb6aO3eu8ZlZvnw5u+eee1yN+aZNm1hLSwt7/fXXjceeeOIJtnjxYnbLLbew008/3bL9SSedxH7+8587OrYdxZz38/mbdjg5j9NOO4397Gc/M37v6elhLS0t7JlnnjEe+8c//sGWLVvGZFl2fY4EQRCF4Bll6IEHHkBzczMOPPBAAMBPf/pTHHfccZZtenp6MGfOHLz00ks47bTT8POf/xyCIBjP85+7urqwYcMGRCIRLFq0yHi+pqYGM2fOxBtvvAEA2LZtG/r6+jB58mTbc3JyjIGgtbUVF198MebNm4ejjjoq7e7Z2rVrcdhhh8Hn8xmPLVy4EFu2bMG+ffsAAB9++CH8fj9Wr16Ngw8+2LK/07EHgH/+85947bXXsGPHDhx11FG47bbbACTHfsaMGdi0aZMxbvw84vE4JkyYgFgshkWLFhljf9BBB6WN55FHHonOzs6yHnu31zsALF68GOeeey5mz56NJUuWYPXq1QC06/2oo46CoiiW8aqsrAQAvPbaa3jzzTcBaOlK/HqfNGkSmpqajPHcsGED4vE4duzYgffeew9A8cc8GAxaxsoJzz33HD772c9i9uzZOPvss7Fr1y7juf3792PLli2W1+3z+XDooYdazvn555/Hl770JSNdrLa21tVcw1OhHn30URx33HH4yle+AkB7//k8MX78eOzevRsPPfQQPvOZz8Dv91vmmlgshokTJ1pSzaZOnYoXX3wRsVjMuN5PPvlkPPnkk+jv73c99qIo4u2330ZXV5fl8QsuuAAPPPCA4+MAxR33k08+GQDQ1NQEwP38/uijj+I73/mO8Voef/xxY7x27NiB3bt34+GHH0Zzc7Oh6vA55nOf+1zG74q+vj7jNZxyyim4//77XY35lClT0NTUhLfeest47OWXX8aRRx6JI488Ehs2bDDmgfb2dnzyySc48sgjHR271PO+GzZv3oz/+q//MuYePu87PY8RI0bgxRdfxI4dO6AoCh544AEEAgFMnz7d2OfII49ET08Pnn322bzPkyAIIh88Eww9//zzOProo43fP/e5z2H79u1Yu3at8diTTz6JmpoaLFmyBFOmTMHcuXMtx/jDH/6AUaNGYdq0aWhtbQUAjB492rJNY2Oj8dzGjRsBAH/+85+xbNkyHHfccbjmmmuMhb+TY5QanrbR0dGBv/zlL7j55ptx5513WrZpbW010knM5wgAu3fvBgAsW7YMv/71rzFu3Li0v+F07AEtGDrrrLPw9NNP46yzzsKNN96IV199FX/4wx8gSRJaWlos42Y+j4qKCuNx89ivX78ef/vb34yx9/v9xoKxXMfe7fUOaIvTM844A08++STOOussPPDAA6irq8O0adMsYwsAiUQCd999N2pqatDR0YE9e/YYwZH5ek8kEti2bZvxWgBg1qxZeOGFFyyvp9Axl2UZL730Ev7+97/j9NNPd7zfW2+9hW984xv4zGc+g9WrV2P58uW4/fbbjeedfkZ/+tOf4sILL0QgEAAAyyLMyVwzfvx4AFqa3I033oj58+fD5/Ph5ptvNv7O4sWL8ac//QkzZswAAEiSlDbXyLKMww8/HLNmzcLcuXNxySWXYM+ePZbXMXv2bNTV1eFf//qX67E/77zzsG7dOhx11FG44IILcPvtt+O9995DdXU1Jk2a5Pg4xR73F1980bKd2/n9wQcfxLhx49DQ0ICamhpcf/31xt+fPn26Me6VlZWQZRlAcsxfeukl/Pd//7dlfv/DH/6Ampoay2tYunQpNm3ahKqqKldjvmjRIrz99tvG76+88goWL16MOXPmoLq6Gq+88goA4M0330QoFMIhhxyS85gDMe+74S9/+Ytl7uHzvtPzuPLKK+H3+3Hsscdi9uzZuOmmm3DLLbcYnysA8Pv9WLx4sWXuIQiCGAg8EQypqor3338fLS0txmPTp0/HrFmzjLvfgJajftppp0GSpLRj/PznP8dLL72EH//4x/D7/UaRNl/8cILBIGKxGADty1IURTQ2NuL3v/89vv/97+OVV17B17/+daiq6ugYTnn88ccxb948y7/zzjsv536vvvoqPv74Y/ziF7/ArFmzMG/ePPzsZz+zbBONRm3PEUDO83Qz9oBWV3LGGWdg3Lhx+PrXv47q6mr85je/wUsvvYT6+nqEQiHLuJnPg9+NDQQClrFfuHAhJkyYYBn7UaNGGdumvq6hPvaMsbyu97PPPtsYex6wL126NO16l2UZV1xxBT7++GPMnTsXsVjMeD71eo9EInjxxRct13tLS4uluLkYYz579mysWrUKX/va1/Dd737X8XH+8pe/YP78+bj00ksxadIkfOELX8AXv/hF43m3n1FVVQEkFQrA3Vxz7bXX4qmnnsIbb7yBr371q9i9ezf27t1rew4ALHMNAOzduxdjxozBN77xDdTU1OC1117DOeecY7yf/BhTp07F22+/7XrsTzzxRPz1r3/Fsccei3fffRe//OUv8YUvfAEnnniioQ46oZjjzucYM27n90mTJuGtt97CqlWrjCDB7u+b9800v5966ql48cUXsXz5cssxJk6cCL/fj97eXldjzoMhxhg2bNiAvXv3YvHixZAkCYsWLTLqht544w0ceuihxvyQjVLP+24xzz183udGGE7OY9OmTaiursZvf/tbPPDAA/jc5z6Hyy67DOvXr7fsd+CBB1rmHoIgiIHAE8FQZ2cnZFlOKypdsWIFnnrqKcTjcWzduhVvv/02VqxYYdkmkUjgBz/4Ae6++26sWrXKSL0IhUIAkFYIG4vFEA6HAQAXX3wx/vOf/+DrX/86WlpacNxxx+H666/H66+/jvfff9/RMZyybNky/O1vf7P8u/baa3Put3HjRtTW1lruoM2YMcM4N/5a7c4RgKEYZMLN2APagoGTSCSgKArefPNNrFq1Cg0NDYjH45ZxM58HX4jG43HL2AeDQYwZM8Yy9nV1dca2qa9rqI+9LMt5Xe8TJ060XO91dXXGHV9+Tu3t7bjooovwwgsv4De/+Q0qKioQDocRCoUQCATSrvexY8di3759luu9trbWSG/hryffMX/sscdw9dVXo6amBkcccQQuuugiV2lyGzduxOzZsy2PzZs3z/jZ7WeUu5FVVVVZHncy1wDA7bffbsw1PN1JFEXbcwBgmWsWLlwIAPjjH/+Iiy66CL/+9a/R29uLbdu24eOPP7Yco6GhAfv27ctr7OfOnWvcuX/sscfw7W9/G729vTj//PMdu5gVc9z5HJOKkzFXFAUA8Le//c2Y37miY/f3FUUxbrqkzu9HH300Jk2ahNbWVlx44YWGQsOPIUkS6urqEIlEXI35okWL0NnZiU8//RSvvPIKZs6ciYaGBgCaWsgd5dauXYsjjjjC0TFLPe+7xTzvA1r6LP9buc5j9+7d+O53v4vvfve7OO644zB79mxcc801mDZtGn79619b9uPXPUEQxEDiiWCIf3nxxTLns5/9LGKxGF588UWsXr0ac+bMwZQpU4zn+Rf8448/jhtvvNFiccpTH7hbDaetrc24KyyKIurr6y3P8zqC1tZWR8dwSmVlJSZMmGD55+QYgiCkjQsAy4KyubnZ9hwB5PwbbsYeSN555WPf19eHz3zmM/jCF75gnId53Mznwe8mt7W1Wcaej6d57PlitZzH3u31Lsuy5XqvrKw0nLP4mJ9zzjl45513cOedd+Loo482xqu5uRldXV1GqhzHnBLKj9HT02Ms8PnryXfMJ06ciNNOOw0333wzHn74YfzkJz9xdRy798Dv9xs/u/2M5jvX8MXdE088kTbXcBUz9RwURbHMNePGjUNTUxNqa2sBJOeayspKYzHJj6EoCkRRdDX2ra2tuPrqq40UL1EUMXPmTFx88cW4++67EYlEHNfCFHPczbU6ZpzM73/84x8BIG3MzX/PTCQSMeYo8xzD5yuesjZr1izb16AoCnp7e11d701NTZg0aRLefvtt/Pvf/7bUBB155JFoa2vDhx9+iA0bNmDx4sWOjlnqucctdmodn3tynce7776LRCKRFlwffPDB2Lp1q+UxczBLEAQxUHgiGKqvr4ff70+zZK2pqcHxxx+P5557Ds888ww+97nPGc/F43FceOGFeO+993DnnXfipJNOsuw7ffp0VFVVYc2aNcZj3d3dWLduHRYsWAAAuOKKK/Bf//Vflv14OsfUqVMdHaPUzJgxAz09PcadYwDYsmULent7jd8XLFiAN99807iLCmhF85MmTcpp4Vro2I8cORJTp061nMeBBx5ojBs/D7/fj61btyIYDGLNmjXG2JvH0zz2gUAAgiCU5dj7/X7XYw4Ad999d8brffTo0RAEAXv37sW9996LBQsWWMbrkEMOgaIollSnzZs3G4sW8/W+adMmI+e/WGO+cOFCnHvuufjrX/+Kf/3rX473mz59uqUeA4ClT82IESMwadIky3UiyzLWrl1re858cRyJRCyP57re7777bgCwHfvJkyenzROx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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Filter data for each year once\n", + "years = ['y2020', 'y2025', 'y2030', 'y2035', 'y2040', 'y2045', 'y2050']\n", + "pe_imp_data = {year: data_results['vQPEImp'][data_results['vQPEImp'].sYear == year] for year in years}\n", + "\n", + "# Define the list of prefixes to drop\n", + "drop_prefixes = ['sPEHYDRR', 'sPEHYDRC', 'sPEMNHY', 'sPEWINON', 'sPEWINOF', 'sPESOLPV', 'sPESOLTE', 'sPESOLTH', 'sPEBIOMEC', 'sPEBIOMAW', 'sPEBIOMFW', 'sPESWAST', 'sPEBIOETHPI', 'sPEBIODIEPI', 'sPEBIOGAS', 'sPEHUMANE']\n", + "\n", + "# Function to filter out rows with specified prefixes\n", + "def filter_prefixes(df, prefixes):\n", + " mask = ~df.sPE.str.startswith(tuple(prefixes))\n", + " return df[mask]\n", + "\n", + "# Apply the filter to each year's data\n", + "pe_imp_filtered = {year: filter_prefixes(pe_imp_data[year], drop_prefixes) for year in years}\n", + "\n", + "# Set index and plot for each year\n", + "for year in years:\n", + " pe_imp_filtered[year] = pe_imp_filtered[year].set_index(['sPE', 'sYear', 'sSeason', 'sDay', 'sHour'])\n", + " pe_imp_filtered[year].unstack('sPE').plot()\n", + " plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')\n", + " plt.title(f'Primary Energy Imported (vQPEImp) for {year}')\n", + " plt.ylabel('[GWh]')\n", + " plt.xlabel('Hour')\n", + " plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Primary energy produced at the domestic level" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1wAAAHJCAYAAACR0TgdAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdd3gUxRvA8e9deu+FUAIJUgKEHpp0QiABRIoFkSIGDU1BCIYiAREUkF6kCkj/0RQQQ6gq0rt0EIihJJByKaTf/f44bslxl0oaMp/n4SHZnZ2d3b0k997MvCNTqVQqBEEQBEEQBEEQhCInL+0GCIIgCIIgCIIg/FeJgEsQBEEQBEEQBKGYiIBLEARBEARBEAShmIiASxAEQRAEQRAEoZiIgEsQBEEQBEEQBKGYiIBLEARBEARBEAShmIiASxAEQRAEQRAEoZiIgEsQBEEQBEEQBKGYiIBLEAThBWI9eEEQBEEQiophaTdA+G/78MMPOXnypNY2IyMjHB0dadu2LZ9//jk2NjY5Hh8ZGUn79u2ZPn06PXr0KO7mFpkTJ07Qr1+/XMssX76cVq1alVCLike7du24f/++9L1cLsfCwoI33niDd999l+7du5de4wohPT2dWbNmUbt2bbp16wbAl19+ycmTJzl48OBL1//1119jaWnJyJEj832MSqVi165dbN26lRs3bpCWlkb58uXx8/Ojb9++2NnZaZWvXr26Th0mJiZUrFiR7t27M2jQIORy9Wdt+n4+s6tbty5btmzRW1Ymk2FmZkaVKlXo3r07ffr0wdCwZP6kzJs3j7i4OEJDQ/MsO3PmTP73v/+Rnp5OaGhokb8m7927x+zZszlz5gwpKSlUq1aNESNG0KxZM61ya9asYd26dURFReHp6cnnn39O69atpf1KpZLNmzezYcMGIiMjsbe3p3379owYMQJLS0ut802fPp3Tp09jYGBAp06dGDNmjFYZQRAEoWwRAZdQ7Ly8vJg0aZL0fUZGBpcvX2b27NlcvXqVjRs3IpPJ9B7r7OzM5s2bqVSpUkk1t0h99dVX1KpVS+8+T0/PEm5N8WjdujVDhgwBIDMzk7i4OPbu3cvYsWO5evUqISEhpdzC/IuOjmbNmjVMnz5d2jZkyJA8g+f8OHbsGOHh4YSFheX7mPT0dD7//HOOHDlCz549GThwIKamply6dIm1a9eyfft2fvjhB50gq1evXvTu3Vv6PiUlhX379jFr1iwSEhL44osvpH0v/nxmZ2FhofV99rJZWVkoFAp+//13KQCYO3euFMwVp8GDB+Pn54efn59OYJPdjRs3WLFiBe+88w5vvfUWHh4eRdqOuLg4+vbti62tLePGjcPS0pL//e9/fPTRR6xZswYfHx8AfvzxR2bOnMnQoUOpXbs227ZtIygoiLVr19KoUSMAVqxYwdy5cxk0aBDNmjXjzp07zJ8/n5s3b7Jq1SpkMhkJCQn0798fR0dHvv32W2JjY5k5cyaRkZGsXLmySK9NEARBKEIqQShGffv2VfXt21fvvoULF6qqVaumOnfuXMk2qgQcP35cVa1aNdXx48dLuynFqm3btqqxY8fq3Tdt2jRVtWrVVKdPny7hVhXev//+q6pWrZpq27ZtRV53165dVStXrizQMTNnzlR5eXmp/vjjD5190dHRqo4dO6o6duyoSklJkbZXq1ZNNX/+fL319evXT1W/fn1Venq6SqXK/efzRbmVXbNmjapatWqqn3/+OV91FYUVK1aounbtmmuZEydOqKpVq6Y6duxYsbRh1apVqlq1aqkePXokbcvMzFQFBASoBg8erFKpVKqUlBRVo0aNVDNmzJDKKJVK1TvvvKMaMGCASqVSqbKyslSNGjVShYaGatW/Z88eVbVq1VQXL15UqVQq1Q8//KCqW7euKiYmRipz+PDhV+7nTBAE4XUj5nAJpaZ27doAPHjwAFAPWRo9ejQjRoygXr16DBw4kMjISKpXr8727dsB2L59O3Xq1OH06dP07NmTOnXq4Ofnx8GDB/nnn3/o378/devWxdfXlz179mid79SpUwwaNIjGjRtTu3Zt2rVrx4IFC1AqlQDSuX788Uc6depE3bp1Wb9+PdWrV2fz5s1adT18+JCaNWvyyy+/vPR92L59O15eXly4cIF3332XOnXq0LZtW51PrNPS0pgxYwatW7emdu3adO3alV9//VWrTLt27Zg2bRr9+/fH29ub8ePHA3D79m0CAwNp0KABzZs3Z86cOYSEhPDhhx8CMGLECFq1aiXdC43x48fj5+dXqOsaNmwYJiYmbNq0SesaFi1aRKdOnahTpw4dO3Zk2bJlWuf98MMP+eqrr1i8eDEtW7akbt26BAYG8uTJE7Zt24avry/169dnwIABREZGap1z//799OjRgzp16tCiRQumTp3K06dPpf2pqamEhobSqlUrateuTadOnaT7rBm+ChASEkK7du0A9ZBCzdegHuK3evVqOnfujLe3N76+vqxcuTLXeV+HDx/mxo0bBAQEAHD27FmqV6/OoUOHtMpdvXqV6tWrEx4eTlJSEmvXrqVnz568+eabOnU6OTkxfvx47t69y+7du3N/GM/Url2b5ORkFApFvsrnV9++fXFxcdF61llZWaxfv56uXbvi7e1NmzZtmDVrFmlpaVKZL7/8kkGDBrF582Y6dOiAt7c37733Hnfu3OHQoUN07dqVunXr0rt3b65evap1zi5dunDz5k0OHz6st00LFiyQXt/9+/eXnmF+29W/f38mTZpEgwYN8Pf3JysrS+ccLi4uDBgwABcXF2mbgYEB7u7uREREAHDhwgUSEhLw9fWVyshkMnx9fTlx4gSpqakkJSXx1ltv0aVLF636NT1y//77LwB//vknDRs2xN7eXirz5ptvYmFhwe+//673PgiCIAilTwwpFErNnTt3AKhYsaK0be/evXTr1o0lS5bovPnXyMzM5IsvvmDYsGGUK1eOWbNmMXr0aBwdHXn//ff59NNPWbhwIWPHjqVhw4a4urpy7do1BgwYQKdOnZgzZ440L2bhwoV4eHhIb4RB/UZt/PjxWFpaUrduXX7++Wd+/vln3n33XanMzp07MTc3p2PHjrleo1KpJDMzU2e7TCbDwMBAq9znn3/OgAED+Pzzz9m6dSszZsygWrVqtGzZEpVKxdChQzl79iwjRozA09OT8PBwRo4cSXp6uta8lPXr1zNw4EACAwOxsLAgNjaWvn374uDgwPTp08nKymLevHk8ePCAevXqAeohaGFhYZw4cUIaopWamspvv/1GYGBgrteYEysrK7y9vTlz5gygDlQ+/fRTzp8/z7Bhw6hRowYnTpxg7ty5/Pvvv3z99dfSsbt376ZWrVp88803PHr0iClTptC3b19MTEwYO3YsKSkpfPXVV0yZMoVly5YBsGvXLkaPHk3Xrl35/PPPuX//PnPmzOHWrVv8+OOPyGQypk2bxp9//snYsWNxdHTk999/Z8aMGdja2tK1a1cWLlzIsGHDCAoKyvHZzpgxgzVr1jBw4EBatGjBpUuXmDVrFpmZmXzyySd6j/nll1+oV6+e9Ma8QYMGVKpUiT179tC2bVut67a1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uITXgre3N3v37mXjxo14enpy7do1lixZgkwmIyUlJV919OzZk++//55WrVrle/jOrVu3cgxanJycck2IkF3r1q1p3LgxQ4YMYciQIXh6enLx4kXmz59Py5Ytcx3i1q9fP9avX8+gQYOk+UqLFy8mIyNDZ96Hn58fX3/9NRcvXmTixIn5altsbKwUvGVlZRETE0NYWBi7d+/m008/lXpaWrVqRZMmTZgwYQJRUVHUqFGDkydPsnz5ct5++20pwUFhGBgYMHLkSL766isMDAxo27YtCQkJLF68mKioKGrVqoWpqSm1atVi4cKFGBkZUb16de7cucOOHTukBCKaN7nHjh3D09NTax4RqIcS9uvXj9WrV2NsbIyPjw8XLlxg48aNBAcH57job4sWLTh79qzOdk1Gwg0bNlC/fn2dnsphw4Zx9+5dgoKC6NWrF+3atcPf35+IiAjmzJkDwHfffZev4XQ5SUpK0ht8a9SpU0cKJLOXVSqVxMXF8eeff7J582a6desm9bJUrVqVt99+m/nz55OSkkLjxo25evUqCxcupEmTJrRs2bLQ7c3u7NmzBaqrqNs1f/587t69y/DhwzE0NNS6j8bGxnh5eWFmZsZHH33EokWLMDIyon79+mzbto3Lly9LPdaPHz9m+vTplC9fng8++IArV65onadSpUrY29vTp08f1q1bx8CBAxk2bBjx8fHMnDmTVq1a5TjcWBAEQSh9IuASXgtffvklGRkZzJ07l/T0dCpUqEBQUBC3bt3i4MGDetfYeVHr1q35/vvv6dGjR77PO2XKlBz39evXT1onKy9yuZxly5Yxb948li5dSkxMDC4uLgwcODDPpA/W1tasXbuWb775huDgYCwsLOjTpw9mZmY682RMTExo2rQp//zzj9bwp9wcOXKEI0eOAOr5QtbW1nh5eTF//nytTIgymYylS5cyf/58Vq9eTWxsLBUqVGDUqFFSdsmX0bt3bywsLFixYgWbN2/G3NycBg0aMGvWLGnY1pQpU5g7dy6rVq3i8ePHODg40KtXLz777DNA3as0cOBANm/ezJEjRzh69KjOecaMGYODgwObNm1ixYoVVKhQgYkTJ/Lee+/l2DY/Pz927dpFVFSUTrD+1ltvsX//frp27apznJGREfPmzWP37t1s2bKF4OBg0tLSKFeuHIMGDSIhIYHx48dz4sQJvv76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jYQ0uCQSiUQikUgkEomkkWhWBlcgEODSSy9l48aNdSq/du1arr76avr378/w4cN54IEHKCoqCp3XdZ1Zs2YxfPhwMjIymDx5Mnv37g2rY+nSpVxyySX07duXUaNG8cQTT+DxeELnvV4vM2bMYOjQofTt25e7776bgoKCej3XqFGj6NatW7Wvt99+u151Aezbt49u3bqxYsWK0LFffvmFiy++mD59+jB27Fjmz59f4/XTpk3j3nvvDTtWm+wPv2dNsg+2Iz09ncGDBzNw4MAw2VeWZ+/evRk0aBAZGRkh2c+ZM4dHHnkEOPllX9f+Hrzn22+/fcT+/uGHHzJ06FC6detGWloaY8eOZc+ePaHzhYWFXHXVVXTv3p1u3brRr18/Zs6cGervjz76KHPmzGkUmaenpzN69GieffZZdF2vV32H8/zzzzNq1KjQ/3X5ngcpLCzk9NNP5+eff66Xrrn//vvp3bt3nXXNOeecw8SJE8PqWLp0KRdeeCE9evQgLS2N9PR07rzzzpB8vV4vZ511Fv379z9q2QshePPNN7nwwgtJT0+nf//+XHnllXz11Vf1qqc6jlXuw4YN49xzz62Xfh85ciRpaWl11u9PPvkkV199dahMUL+np6fTq1cvevbsyciRI0N63uv18tBDD9G9e3cyMjLqLfMJEyZw5513Vjl++umn061bN/bv3x92/KWXXmLAgAEEAoE63yNIY+j9o7lnddTWjrKyMmbMmMHpp5/OgAEDmDx5Mjt27Aidf+ONN0J6XyKRSE5GmpXBNXfuXLp06UKvXr1qLbtr1y5uuOEGunXrxgcffMC///1v1q9fz//93/+Fyrz44ou88847PPzww7z33nvous6kSZPw+XwArF69mttvv53Ro0fzySef8I9//IMFCxYwY8aMUB3Tp0/nxx9/5Pnnn+eNN95g586d3HHHHfV+tuuvv54ff/yxyuuSSy6pd12Hs2PHDm666SaGDx/Oxx9/zGWXXcbUqVP55Zdfwsrpus4zzzzD+++/X6WOhpD9jTfeGGrHpZdeitfrxeVycd9994VkP23aNH788Uduu+02AoEAVquVLl26hGS/fft2fvjhB1avXn3Sy74+Mgd48skna+zvn3/+OdOmTcPj8fDII49w9913k5mZycSJE0P9/S9/+QurVq3iz3/+M48//jh2u50PP/ww1N9vv/12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dlno3JF0zebNm4UQh3RNnz59RGpqqrjzzjvrLXu/3y9ef/11MWHCBNG3b1/Rq1cvMW7cODF79mzh8/nCnvd4yj2YE+7wtk+dOlV07969XjJ/6qmnRGpqarX3v/3228VVV11Vq8yDr23btoV0TK9evcTpp59eb5kLcSiv1D//+c8q595++22RmpoqVq5cWa96G1vv16UdNeXhSk1NFR999FGd25GVlSXuuusuMWzYMDFgwADxl7/8JdTvg+Tn54u0tDSxYcOGGp9BIpFITlSajcFVWFgo+vbtK9avXx923OVyiYyMDPHTTz81UctqZ/r06WLdunVNdv2xEpT9X//617B2NJXs58yZIy6//PI6lT1RZX94fw+2o6n7+4wZM8Tdd999xDINKbNAIFAlaWpjU52uCQQCYsKECc1C19x4443imWeeqfZcQ8n+eMu9Jv1eXFws0tLSmlzmXq9XDBo0qNp2NJaOaGq939zaUR+9L5FIJCcazcalMDY2luuvv57XX38dMPzoFy1axAMPPEDr1q3rvNn4eJOZmcnmzZvp0aNHk1zfEMTGxnLJJZewcuVKevTo0aSy9/l8vPvuu3WKIngiy75yf8/MzGTDhg3s37+/Sft7YWEhX331FbfddluNZRpaZnPmzDmi619jUJ2umTp1KoFAoMl1zY4dO9iwYQN/+ctfqpxrSNkfb7nXpN+vvPJK4uLimly/f/rpp6SmplaJIthYOqI56P3m1I766H2JRCI5IWlqi68yXq9XTJgwQfz2228iPz9f9O/fX4wePVr8/vvvTd20I1LZVacprm8IvF6vuOiii5pc9q+99pqYMWNGncufyLKv3N+zsrKavL8//PDDYs6cObWWa0iZeb3eBqurvvdtjrrm5ptvFgsXLqzxfEPJvinkXp3Mzz777CaXeVlZmRgzZozIzMys9nxj6YjmoPeFaB7tqK/el0gkkhMNRYhqskRKJBKJRCKRSCQSieSYaTYuhRKJRCKRSCQSiURysiENLolEIpFIJBKJRCJpJKTBJZFIJBKJRCKRSCSNhDS4JBKJRCKRSCQSiaSRkAaXRCKRSCQSiUQikTQS0uCSSCQnFffeey+jRo2q8fyoUaO49957j2OLJBKJRCKRnMpIg0sikUgkEolEIpFIGglpcEkkEolEIpFIJBJJIyENLolEcsqiaRrz5s3j/PPPJz09nREjRvD000/j9XpDZa6++mquvvrqsOtWrFhBt27dWLFiBQAff/wxPXr04MMPP2TYsGEMGjSI7du3H9dnkUgkEolE0jwxN3UDJBKJpDEIBAK1lpk2bRqfffYZkydPZsCAAWzatIn//Oc/bN68mTlz5qAoSp3vp2kar776KjNnzqSwsJDOnTsfS/MlEolEIpGcJEiDSyKRnHTs37+fnj17HrHM9u3b+d///sfdd9/NjTfeCMCwYcNISkpi6tSpfP/995x55pn1uu/NN9/MiBEjjrbZEolEIpFITkKkwSWRSE46WrRowUsvvVTtuVtuuQWAlStXAjBu3Liw8+PGjeO+++5jxYoV9Ta4unfvfhStlUgkEolEcjIjDS6JRHLSYbVa6d27d43nAIqLiwHDOKuM2WwmLi6O0tLSet/X6XTW+xqJRCKRSCQnNzJohkQiOSWJiYkBIDc3N+y43++nsLCQuLi40DFN08LKlJeXN34DJRKJRCKRnBRIg0sikZySDBo0CID58+eHHZ8/fz6aptG/f38AIiMjycrKCiuzZs2a49NIiUQikUgkJzzSpVAikZySdOnShQkTJjBr1izcbjcDBw5k8+bNvPDCCwwePJjhw4cDMHLkSJYuXcpjjz3GqFGjWL16NZ9++mnTNl4ikUgkEskJgzS4JBLJKcvMmTNp3749H330EbNnzyYpKYlrrrmGW2+9FVU1HAAuueQSMjMz+eSTT3jvvfcYOHAgs2bN4vLLL2/i1kskEolEIjkRUIQQoqkbIZFIJBKJRCKRSCQnI3IPl0QikUgkEolEIpE0EtLgkkgkEolEIpFIJJJGQhpcEolEIpFIJBKJRNJISINLIpFIJBKJRCKRSBoJaXBJJBKJRCKRSCQSSSMhDS6JRCKRSCQSiUQiaSSkwSWRSCQSiUQikUgkjYQ0uCQSiUQikUgkEomkkZAGl0QikUgkEolEIpE0EtLgkkgkEolEIpFIJJJGQhpcEolEIpFIJBKJRNJI/D/0IU9LGaFN2wAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Filter data for primary energy domestic capacity once\n", + "filtered_PEDom = data_results['vQPEDom'][~data_results['vQPEDom'].sPE.str.startswith(('sPENUCLE', 'sPEIMPCO', 'sPENAGAS', 'sPELNGAS', 'sPECROIL'))]\n", + "\n", + "# Split the filtered data by year\n", + "PEDom_by_year = {year: filtered_PEDom[filtered_PEDom.sYear == year] for year in ['y2020', 'y2025', 'y2030', 'y2035', 'y2040', 'y2045', 'y2050']}\n", + "\n", + "# Set index and plot for the year 2020\n", + "y2020_PEDom = PEDom_by_year['y2020'].set_index(['sPE', 'sYear', 'sSeason', 'sDay', 'sHour'])\n", + "y2020_PEDom.unstack('sPE').plot()\n", + "\n", + "# Put legend outside of the plot\n", + "plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')\n", + "plt.title('Primary Energy Domestic (vQPEDom) for 2020')\n", + "plt.ylabel('[GWh]')\n", + "plt.xlabel('Hour')\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Total cost per year" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1YAAAHZCAYAAACFJapPAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAACYVUlEQVR4nOzdd1RU58LF4d8MvQgCIiD23mNvsWI31lgSY+/G3qLRmKhJNEaNXWPvGmssiT3GEo29xmDvooAKioUizHx/eOW7XDUBBQdwP2uxVjjnnTN7BqPsOe95j8FsNpsRERERERGR12a0dAAREREREZGUTsVKRERERETkDalYiYiIiIiIvCEVKxERERERkTekYiUiIiIiIvKGVKxERERERETekIqViIiIiIjIG1KxEhEREREReUMqViIikuhS073nU9NrERGRpKNiJSIifP755+TJk+cfv1q1avWvxwkLC2PgwIEcOXIkwc/v5+f3r+NMJhOrVq2iRYsWlC5dmmLFitGoUSMWL15MVFRUgp4zPo4ePUrnzp0T/bivy2w207p1awoWLMj58+dfOmb58uXkyZOHn3766S2nExF5t1lbOoCIiFhet27d+Pjjj2O/nz59Ov7+/kydOjV2m7Oz878e58yZM6xfv57GjRsnesbw8HC6du3KyZMnad68OR07dsTGxoYDBw4wZswY9uzZw7Rp07C1tU2051y1ahWXLl1KtOO9KYPBwMiRI6lfvz5Dhw5l+fLlGI3//xlpYGAgY8eOpUKFCjRv3tyCSUVE3j0qViIiQubMmcmcOXPs9+7u7tja2lKkSBHLhfof3333HceOHWPx4sVxcpUvX568efPSv39/li9fTuvWrS0X8i3IlCkT/fr149tvv2XRokW0bds2dt+wYcOwtrZm5MiRlgsoIvKO0lRAERGJt3379vHJJ59QvHhxSpcuTf/+/bl9+zYABw8ejC01rVu3jp06GBMTw6xZs6hbty6FCxemSJEifPzxxxw4cCDezxsSEsKaNWto3LjxS8te3bp1ad++PV5eXrHbgoODGTx4MJUqVaJw4cI0adKEHTt2vPB6mjVrRtGiRSlZsiSffvpp7Bmqzz//nLVr1xIQEECePHn4+eefX5ptypQp+Pn5sXPnTmrVqsV7771Hs2bNOHjwYJxx9+/f56uvvqJcuXIUKlSIZs2asX///jhj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WquTvweAtudvf/ubFixYoJEjR2rVqlWSmgPQfy+kb38fFhbm0r5x40a98MILuvfee5WVleXc//J9vtXQ0NBif1ydN2ojSb/5zW/U0NCgyMhISVJSUpLOnTunN998U5mZmc5TB/Hd3K1PcnKyJGn16tXKyMjQp59+qieffPKG+sCVeas2zz//vJ566innabQ2m03BwcH62c9+pqysLMXFxXl7au1Ca+rz1ltvqa6uTpmZmVftl7XjGd6qD+vHfa2pTXR0tHbs2KGwsDAFBwdLkoYNG6a8vDxt2LBBS5cuZe20Et+W4OL9999XZmamMjIy9NZbbzkDUc+ePVVZWemybWVlpcLDw51fxiVp5cqVeu655/TII4/ol7/8pfMLedeuXRUeHn7FPi6/9gdX563aSM3/C3X5tlLzP3C1tbWqrq724qzaj9bW5/jx4/rLX/7i8np4eLh69+7t3O96a4wr82ZtOnXq1OLaxMGDB0sSpzlfp9bW59NPP1VRUZHGjBmjESNGaMqUKZKkH/3oR1qyZMl19YFr82Z9WD/uced7QVRUlDNUSc3XXg8cOND5OAnWTusQrOCUnZ2tF154QTNmzNCrr77qcgh41KhR+uabb1y237Ztm0aOHOn8gr5y5UqtW7dOTz31lJ5++mnnNQhS80WVI0eObNHH9u3br3qKAC7xZm2MMbrzzju1du1alz727dun7t27Oy/Sx9W5U5/8/HzNmzdPxcXFztftdrsOHTrkvLD4emqMK/N2bR5++GE988wzLn3s27dPwcHB6tevn/cm1k64U58NGzZo8+bN+vzzz/X555/r7bffliS9+OKLmjdv3nX1ge/m7fqwflrPndr885//1IgRI3T06FHn6xcuXFB+fr4GDRp0XX3gKvx0N0K0McXFxSYlJcX85Cc/afFMA7vdbgoLC01KSopZuXKlKSoqMuvXr3d5nsG2bduMzWYzL7zwQov9z507Z4wx5quvvjLJycnmnXfeMUVFRebll182aWlpPMfqGnxRm+XLl5ubbrrJbN682ZSUlJgPP/zQpKWlmY8++sifUw8I7tanoaHB3HvvveaBBx4w+/btM/v37zePPvqouf32283Zs2eNMeaafeDKfFGbDRs2mOTkZJOdnW2OHDliNm/ebMaMGWNeffVVf049ILhbn/929OjRFrfzZu20ni/qw/ppHXdrc/bsWZORkWEeeughs2/fPpOfn2/mz59v0tPTzYkTJ4wxrJ3WIljBGGPMm2++aWw22xV/nnrqKWOMMf/4xz/MlClTTGpqqrnnnnvM5s2bnfsvWrToqvu//vrrzu0+++wzc9ddd5lhw4aZ6dOns0Cvgy9qc/78ebN27Vpzxx13mJSUFHP33XcTqq6Tu/UxxpiKigozf/58M2bMGDNixAiTmZlpysrKXLa5Vh9oyVe1ef/99833v/99k5qaajIyMsybb75pmpqafDbPQOWJ+lzuSl/cb7QPXOKr+rB+bpwnalNSUmIyMzPN6NGjzfDhw82cOXNMQUGByzasnRtnMYab0QMAAACAOzhJEgAAAADcRLACAAAAADcRrAAAAADATQQrAAAAAHATwQoAAAAA3ESwAgAAAAA3EawAAAAAwE0EKwBAu/TMM88oKSlJ//rXv674+ldffaWkpCStWrXKxyMDALRHPCAYANAu2e12TZ48WcHBwfrTn/6k8PBw52vnzp3T1KlTFRkZqU8++UQhISF+HCkAoD3giBUAoF2KiorS0qVLVVpaqtdee83ltVdeeUUnTpzQihUrCFUAAI8gWAEA2q3bb79dU6dO1fvvv689e/ZIknJzc7Vx40bNnTtXQ4YMUVlZmebPn6/Ro0dr+PDhevTRR5WXl+fSz7Fjx5SVlaVbbrlFKSkpGjdunLKysnTmzBmX93rppZf06KOPKi0tTc8++6xP5woA8C9OBQQAtGtVVVWaPHmyevbsqezsbN1///2KiIjQBx98oOrqak2bNk1hYWF68sknFRYWpvfee0/79+/XJ598ooEDB6qurk6TJ09Wt27d9PjjjysyMlK7d+/W2rVrdf/99+v555+X1BysKioqNHv2bI0dO1YREREaMWKEn2cPAPCVTv4eAAAA3tS1a1c999xzevLJJzVnzhwdO3ZMn3/+uYKCgvTee++pqqpKGzduVGJioiRp/PjxmjRpktasWaPXX39dhw8fVkJCgl5++WX16dNHkjR27Fjt2bNH33zzjct79erVSwsWLPD5HAEA/kewAgC0e3fddZcmTZqkLVu2aMmSJerbt68kKScnR8nJyYqPj9eFCxckSVarVePHj9cf//hHSVJycrKys7PlcDh0+PBhlZSUqKioSMXFxc59vpWcnOzbiQEA2gyCFQCgQ7j11lu1ZcsWTZgwwdlWVVWlkpISpaSkXHGfuro6hYWF6be//a3eeustVVVVKS4uTqmpqQoLC9PZs2ddtr/8zoMAgI6FYAUA6LAiIyM1evRoZWVlXfH1kJAQbdq0ScuXL9fChQt13333KSYmRpI0b9487du3z5fDBQC0YQQrAECHNXr0aG3atEn9+/dXly5dnO0vvviizp8/r6VLlyo3N1dRUVF67LHHnK/X1NQoNzdXnTrxzygAoBm3WwcAdFizZs2Sw+HQrFmztGXLFuXk5Gjx4sXasGGD+vfvL0lKS0uT3W7X8uXLtX37dm3atEkzZszQyZMnVVdX5+cZAADaCv6rDQDQYcXHx+vDDz/UK6+8oueee04NDQ3q16+fli1bpgceeECSNH36dB07dkyffvqpsrOzFR8frwkTJugHP/iBFi9erIMHD2rgwIF+ngkAwN94jhUAAAAAuIlTAQEAAADATQQrAAAAAHATwQoAAAAA3ESwAgAAAAA3EawAAAAAwE0EKwAAAABwE8EKAAAAANxEsAIAAAAANxGsAAAAAMBNBCsAAAAAcBPBCgAAAADcRLACAAAAADf9fyZSl16W3yFEAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Group by 'sYear' and aggregate the sums for each cost type\n", + "total_costs = data_results['vTotalCost'].groupby('sYear').vTotalCost.sum()\n", + "op_costs = data_results['vOpCost'].groupby('sYear').vOpCost.sum()\n", + "inv_cost_ce = data_results['vInvCostCE'].groupby('sYear').vInvCostCE.sum()\n", + "inv_cost_st = data_results['vInvCostST'].groupby('sYear').vInvCostST.sum()\n", + "\n", + "# Extract the values for each year\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "TotalCost = [total_costs[f'y{year}'] for year in years]\n", + "OperationalCost = [1e-3 * op_costs[f'y{year}'] for year in years]\n", + "TotalInvCE = [inv_cost_ce[f'y{year}'] for year in years]\n", + "TotalInvST = [inv_cost_st[f'y{year}'] for year in years]\n", + "\n", + "# Plot the results\n", + "plt.figure(figsize=(10, 5))\n", + "plt.plot(years, TotalCost, 'ko-')\n", + "plt.bar(years, OperationalCost)\n", + "plt.bar(years, TotalInvCE, bottom=OperationalCost)\n", + "plt.bar(years, TotalInvST, bottom=np.array(OperationalCost) + np.array(TotalInvCE))\n", + "plt.title('Total Cost per Year')\n", + "plt.legend(['Total Cost', 'Operational Cost', 'Total Inv CE', 'Total Inv ST'])\n", + "plt.xlabel('Year')\n", + "plt.ylabel('Total Cost [GEuro]')\n", + "plt.grid()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Total operational costs per year" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\n", + "\n", + "# Set index for required dataframes\n", + "pPECost = data_input['pPECost'].set_index('sPE')\n", + "pCEFixom = data_input['pCEFixom'].set_index('sCE')\n", + "pSTFixom = data_input['pSTFixom'].set_index('sST')\n", + "pSTVarom = data_input['pSTVarom'].set_index(['sST', 'sES'])\n", + "pESNSCost = data_input['pESNSCost'].pESNSCost.sum()\n", + "\n", + "YrGap = data_input['pYrGap'].pYrGap.sum()\n", + "DisRate = data_input['pDisRate'].pDisRate.sum()\n", + "\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "op_costs = []\n", + "total_cost_vQPEtoCE = []\n", + "total_CE_active_fixom_cost = []\n", + "total_ST_cap_fixom = []\n", + "total_varom_ST_cost = []\n", + "total_ESNS_cost = []\n", + "total_op_varom_cost = []\n", + "\n", + "for year in years:\n", + " y_op_cost = data_results['vOpCost'][data_results['vOpCost'].sYear == f'y{year}'].vOpCost.sum()\n", + " op_costs.append(y_op_cost)\n", + "\n", + " vQPEImp = data_results['vQPEImp'][data_results['vQPEImp'].sYear == f'y{year}'].groupby('sPE').sum().vQPEImp\n", + " vQPEDom = data_results['vQPEDom'][data_results['vQPEDom'].sYear == f'y{year}'].groupby('sPE').sum().vQPEDom\n", + " total_cost_vQPEtoCE.append(((vQPEImp + vQPEDom) * pPECost[pPECost.sYear == f'y{year}'].pPECost).sum() * YrGap * (1 / ((1 + DisRate) ** (YrGap * (years.index(year))))))\n", + " \n", + " vCEActCap = data_results['vCEActCap'][data_results['vCEActCap'].sYear == f'y{year}'].groupby('sCE').sum().vCEActCap\n", + " total_CE_active_fixom_cost.append((vCEActCap * pCEFixom.pCEFixom).sum() * YrGap * (1 / ((1 + DisRate) ** (YrGap * (years.index(year))))))\n", + "\n", + " vSTTotCap = data_results['vSTTotCap'][data_results['vSTTotCap'].sYear == f'y{year}'].groupby('sST').sum().vSTTotCap\n", + " total_ST_cap_fixom.append((vSTTotCap * pSTFixom.pSTFixom).sum() * 1e-6)\n", + "\n", + " vQSTOut = data_results['vQSTOut'][data_results['vQSTOut'].sYear == f'y{year}'].groupby(['sST', 'sES']).sum().vQSTOut\n", + " pSTVarom_ALIGNED = pSTVarom.reindex(vQSTOut.index)\n", + " total_varom_ST_cost.append((pSTVarom_ALIGNED['pSTVarom'] * vQSTOut * YrGap * (1 / ((1 + DisRate) ** (YrGap * (years.index(year)))))).sum() * 1e-6)\n", + "\n", + " vQESNS = data_results['vQESNS'][data_results['vQESNS'].sYear == f'y{year}'].groupby(['sST', 'sES']).sum().vQESNS\n", + " total_ESNS_cost.append((vQESNS.sum() * pESNSCost * YrGap * (1 / ((1 + DisRate) ** (YrGap * (years.index(year)))))))\n", + "\n", + " vOpVarom = data_results['vOpVarom'][data_results['vOpVarom'].sYear == f'y{year}'].vOpVarom.sum()\n", + " total_op_varom_cost.append(vOpVarom * YrGap * (1 / ((1 + DisRate) ** (YrGap * (years.index(year))))))\n", + "\n", + "# Convert to appropriate units\n", + "total_cost_vQPEtoCE = [1e-3 * cost for cost in total_cost_vQPEtoCE]\n", + "total_op_varom_cost = [1e-3 * cost for cost in total_op_varom_cost]\n", + "\n", + "# Plotting\n", + "plt.figure(figsize=(10, 5))\n", + "plt.plot(years, op_costs, 'ko-')\n", + "plt.bar(years, total_cost_vQPEtoCE)\n", + "plt.bar(years, total_CE_active_fixom_cost, bottom=total_cost_vQPEtoCE)\n", + "plt.bar(years, total_ST_cap_fixom, bottom=np.array(total_cost_vQPEtoCE) + np.array(total_CE_active_fixom_cost))\n", + "plt.bar(years, total_varom_ST_cost, bottom=np.array(total_cost_vQPEtoCE) + np.array(total_CE_active_fixom_cost) + np.array(total_ST_cap_fixom))\n", + "plt.bar(years, total_ESNS_cost, bottom=np.array(total_cost_vQPEtoCE) + np.array(total_CE_active_fixom_cost) + np.array(total_ST_cap_fixom) + np.array(total_varom_ST_cost))\n", + "plt.bar(years, total_op_varom_cost, bottom=np.array(total_cost_vQPEtoCE) + np.array(total_CE_active_fixom_cost) + np.array(total_ST_cap_fixom) + np.array(total_varom_ST_cost) + np.array(total_ESNS_cost))\n", + "plt.title('Operational Cost per Year')\n", + "plt.legend(['Operational Cost', 'Total Cost vQPEtoCE', 'Total CE Active Fixom', 'Total ST Cap Fixom', 'Total ST Varom', 'Total ESNS Cost', 'Total Op Varom Cost'])\n", + "plt.xlabel('Year')\n", + "plt.ylabel('Total Cost [MEuro]')\n", + "plt.grid()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Primary energy operational costs" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\n", + "\n", + "TotalCost_vQPEtoCE2020_Imported = (data_results['vQPEImp'][(data_results['vQPEImp'].sYear=='y2020')].groupby('sPE').sum().vQPEImp)*(pPECost[pPECost.sYear=='y2020'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(1-1)))))\n", + "TotalCost_vQPEtoCE2025_Imported = (data_results['vQPEImp'][(data_results['vQPEImp'].sYear=='y2025')].groupby('sPE').sum().vQPEImp)*(pPECost[pPECost.sYear=='y2025'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(2-1)))))\n", + "TotalCost_vQPEtoCE2030_Imported = (data_results['vQPEImp'][(data_results['vQPEImp'].sYear=='y2030')].groupby('sPE').sum().vQPEImp)*(pPECost[pPECost.sYear=='y2030'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(3-1)))))\n", + "TotalCost_vQPEtoCE2035_Imported = (data_results['vQPEImp'][(data_results['vQPEImp'].sYear=='y2035')].groupby('sPE').sum().vQPEImp)*(pPECost[pPECost.sYear=='y2035'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(4-1)))))\n", + "TotalCost_vQPEtoCE2040_Imported = (data_results['vQPEImp'][(data_results['vQPEImp'].sYear=='y2040')].groupby('sPE').sum().vQPEImp)*(pPECost[pPECost.sYear=='y2040'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(5-1)))))\n", + "TotalCost_vQPEtoCE2045_Imported = (data_results['vQPEImp'][(data_results['vQPEImp'].sYear=='y2045')].groupby('sPE').sum().vQPEImp)*(pPECost[pPECost.sYear=='y2045'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(6-1)))))\n", + "TotalCost_vQPEtoCE2050_Imported = (data_results['vQPEImp'][(data_results['vQPEImp'].sYear=='y2050')].groupby('sPE').sum().vQPEImp)*(pPECost[pPECost.sYear=='y2050'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(7-1)))))\n", + "\n", + "TotalCost_vQPEtoCE2020_Domestic = (data_results['vQPEDom'][(data_results['vQPEDom'].sYear=='y2020')].groupby('sPE').sum().vQPEDom)*(pPECost[pPECost.sYear=='y2020'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(1-1)))))\n", + "TotalCost_vQPEtoCE2025_Domestic = (data_results['vQPEDom'][(data_results['vQPEDom'].sYear=='y2025')].groupby('sPE').sum().vQPEDom)*(pPECost[pPECost.sYear=='y2025'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(2-1)))))\n", + "TotalCost_vQPEtoCE2030_Domestic = (data_results['vQPEDom'][(data_results['vQPEDom'].sYear=='y2030')].groupby('sPE').sum().vQPEDom)*(pPECost[pPECost.sYear=='y2030'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(3-1)))))\n", + "TotalCost_vQPEtoCE2035_Domestic = (data_results['vQPEDom'][(data_results['vQPEDom'].sYear=='y2035')].groupby('sPE').sum().vQPEDom)*(pPECost[pPECost.sYear=='y2035'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(4-1)))))\n", + "TotalCost_vQPEtoCE2040_Domestic = (data_results['vQPEDom'][(data_results['vQPEDom'].sYear=='y2040')].groupby('sPE').sum().vQPEDom)*(pPECost[pPECost.sYear=='y2040'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(5-1)))))\n", + "TotalCost_vQPEtoCE2045_Domestic = (data_results['vQPEDom'][(data_results['vQPEDom'].sYear=='y2045')].groupby('sPE').sum().vQPEDom)*(pPECost[pPECost.sYear=='y2045'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(6-1)))))\n", + "TotalCost_vQPEtoCE2050_Domestic = (data_results['vQPEDom'][(data_results['vQPEDom'].sYear=='y2050')].groupby('sPE').sum().vQPEDom)*(pPECost[pPECost.sYear=='y2050'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(7-1)))))\n", + "\n", + "# Now lets graph the operational costs of PE\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "TotalCost_vQPEtoCE_Imported = [1e-3*TotalCost_vQPEtoCE2020_Imported.sum(), 1e-3*TotalCost_vQPEtoCE2025_Imported.sum(), 1e-3*TotalCost_vQPEtoCE2030_Imported.sum(),1e-3* TotalCost_vQPEtoCE2035_Imported.sum(), 1e-3*TotalCost_vQPEtoCE2040_Imported.sum(), 1e-3*TotalCost_vQPEtoCE2045_Imported.sum(), 1e-3*TotalCost_vQPEtoCE2050_Imported.sum()]\n", + "TotalCost_vQPEtoCE_Domestic = [1e-3*TotalCost_vQPEtoCE2020_Domestic.sum(), 1e-3*TotalCost_vQPEtoCE2025_Domestic.sum(), 1e-3*TotalCost_vQPEtoCE2030_Domestic.sum(),1e-3* TotalCost_vQPEtoCE2035_Domestic.sum(), 1e-3*TotalCost_vQPEtoCE2040_Domestic.sum(), 1e-3*TotalCost_vQPEtoCE2045_Domestic.sum(), 1e-3*TotalCost_vQPEtoCE2050_Domestic.sum()]\n", + "TotalCost_vQPEtoCE = [1e-3*TotalCost_vQPEtoCE2020.sum(), 1e-3*TotalCost_vQPEtoCE2025.sum(), 1e-3*TotalCost_vQPEtoCE2030.sum(),1e-3* TotalCost_vQPEtoCE2035.sum(), 1e-3*TotalCost_vQPEtoCE2040.sum(), 1e-3*TotalCost_vQPEtoCE2045.sum(), 1e-3*TotalCost_vQPEtoCE2050.sum()]\n", + "\n", + "plt.figure(figsize=(10, 5))\n", + "plt.plot(years, TotalCost_vQPEtoCE, 'ko-')\n", + "plt.bar(years, TotalCost_vQPEtoCE_Domestic)\n", + "plt.bar(years, TotalCost_vQPEtoCE_Imported, bottom=TotalCost_vQPEtoCE_Domestic)\n", + "plt.title('Operational Cost of PE')\n", + "plt.legend(['Total Cost vQPE to CE','Total Cost vQPE to CE Domestic', 'Total Cost vQPE to CE Imported'])\n", + "plt.xlabel('Year')\n", + "plt.ylabel('Operational Cost [MEuro]')\n", + "plt.grid()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Total investment per year in CE" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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07x583To0CEtXLhQ/fr1c+krW7asZs6cqdmzZ2v37t1asGBBnhQKAAAAAFZwKzStXr1affr0UVRU1DXXady4sbp166bPP//ca8UBAAAAgNXcCk2JiYmqXbv2dddr2LChDh06lOuiAAAAAKCgcCs0BQYG6ty5c9ddz+FwyN/fP9dFAQAAAEBB4VZoqlGjhr7//vvrrrd+/XrdeuutuS4KAAAAAAoKt0LTo48+quXLl+vrr7++5jrffvutli5dqnbt2nmtOAAAAACwmltfpH3ggQf01VdfadCgQWrevLlatGihypUrKysrS0ePHtX69eu1fv16NW/eXJ06dcrrmgEAAAAg37gVmiRpypQpqlatmt5//3199913stlskiTDMBQSEqJnnnlGsbGxstvd/l4uAAAAABR4bocmm82mJ598Ur169dKff/6pY8eOydfXVxUrVlSNGjWcIQoAAAAAChO3Q5NzA19f1a5d260pyAEAAADgRsezdAAAAABggtAEAAAAACYITQAAAABggtAEAAAAACY8Dk0DBw7U2rVrdfHixbyoBwAAAAAKFI9nz0tMTNTgwYNVqlQptW7dWu3atVNUVFRe1AYAAAAAlvM4NK1cuVL79u3T559/rtWrV2vJkiWqXLmy2rZtq3bt2unWW2/NizoBAAAAwBI5eqcpPDxcTz31lL788kt99NFHuv/++7VixQq1bt1anTp18naNAAAAAGCZXE8Eccsttyg8PFzVqlWT3W7XoUOHvFEXAAAAABQIHj+eJ0nnz5/XunXrtHr1av3444+y2+1q3ry53nzzTTVv3tzbNQIAAACAZTwOTU899ZS+//57paenKyoqSqNGjdKDDz6okiVL5kV9AAAAAGApj0PTrl279K9//Utt27ZV5cqV86ImAAAAACgwPA5Na9asyYs6AAAAAKBAytE7TT/++KO+/fZbXbhwQQ6Hw6XPZrPplVde8UpxAAAAAGA1j0PTe++9p0mTJsnf319ly5aVzWZz6f/fZQAAAAC4kXkcmhYsWKCHH35YEyZMkJ+fX17UBAAAAAAFhsffaTpx4oQ6duxIYAIAAABQJHgcmu68807t2bPHawWcOXNGL730kpo1a6aoqCh17txZ8fHxzv4NGzaoffv2ql27tlq3bq1Vq1Z57dgAAAAAcD0eP5734osvaujQoQoMDFTt2rVVvHjxq9ap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n6952x6u8nJ8DMPQfffdpxkzZrjs448//lD58uWdL7wje7kZm507d+qpp57S/v37nf0pKSk6cOCA8wVdd8YX15bX4/PEE09o+PDhLvv4448/VKxYMd122215d2KFRG7GZ/78+Vq1apVWrFihFStWaNasWZKk8ePH66mnnnJrH7i2vB4brp3cyc34fP/996pbt64OHz7s7L906ZJ27typqlWrurUPZMOiWfuQj/bv32/UrFnTGDhw4FXz9aekpBi7d+82atasaUyePNnYu3evMWfOHJe5+jdu3GhEREQY48aNu2r7tLQ0wzAM44cffjBq1KhhvPfee8bevXuN1157zYiMjOQ7TW7Ij/GZOHGiUadOHWPVqlVGQkKCsXjxYiMyMtJYsmSJlade4OV2bDIyMoy2bdsaHTt2NP744w9j27ZtRo8ePYzo6GgjNTXVMAzjuvvAteXH+MyfP9+oUaOGsWjRIuPQoUPGqlWrjEaNGhlTp0618tRvCLkdn/91+PDhq6a15vrJmfwYG66dnMvt+KSmphotW7Y0OnfubPzxxx/Gzp07jWHDhhkNGjQw/vrrL8MwuHZygtBUBLz99ttGREREtn+ef/55wzAMY/369UabNm2Mu+66y2jdurWxatUq5/YjR4685vZvvvmmc71PPvnEuP/++41atWoZMTExXHhuyo/xuXjxojFjxgzj3nvvNWrWrGk88MADBCY35HZsDMMwkpKSjGHDhhmNGjUy6tatawwePNg4evSoyzrX2weyl1/js2DBAuPBBx807rrrLqNly5bG22+/bWRlZeXbed6ovDE+f5fdL+ae7gOX5dfYcO3kjDfGJyEhwRg8eLDRsGFDo3bt2kavXr2MXbt2uazDteMZm2EwGTsAAAAAXAsPLQIAAACACUITAAAAAJggNAEAAACACUITAAAAAJggNAEAAACACUITAAAAAJggNAEAAACACUITAOCGNHz4cFWrVk3//e9/s+3/4YcfVK1aNU2ZMiWfKwMAFDZ83BYAcENKSUnRP//5TxUrVkyff/65AgMDnX1paWl6+OGHVbJkSS1btkx+fn4WVgoAuNFxpwkAcEMKDg7WmDFjdOTIEf373/926Xv99df1119/adKkSQQmAECuEZoAADes6OhoPfzww1qwYIG2bt0qSdq8ebM+/PBDDRkyRNWrV9fRo0c1bNgwNWzYULVr11aPHj20fft2l/0kJiYqLi5O99xzj2rWrKkmTZooLi5Op0+fdjnWK6+8oh49eigyMlIjRozI13MFAFiHx/MAADe0M2fO6J///KduuukmLVq0SB06dFBQUJAWLlyos2fP6pFHHlHx4sU1aNAgFS9eXB988IG2bdumZcuWKTw8XBcuXNA///lPlSlTRv369VPJkiX122+/acaMGerQoYPGjh0r6XJoSkpKUs+ePdW4cWMFBQWpbt26Fp89ACA/+FpdAAAAuVG6dGmNHj1agwYNUq9evZSYmKgVK1bIx8dHH3zwgc6cOaMPP/xQlSpVkiQ1a9ZMDz30kKZNm6Y333xTBw8eVFhYmF577TXdfPPNkqTGjRtr69at+uWXX1yOVbFiRT377LP5fo4AAGsRmgAAN7z7779fDz30kFavXq2XXnpJt956qyRpw4YNqlGjhkJDQ3Xp0iVJkt1uV7NmzfTpp59KkmrUqKFFixbJ4XDo4MGDSkhI0N69e7V//37nNlfUqFEjf08MAFAgEJoAAIVC06ZNtXr1ajVv3tzZdubMGSUkJKhmzZrZbnPhwgUVL15c77//vt555x2dOXNGISEhuuuuu1S8eHGlpqa6rP/3GfoAAEUHoQkAUGiVLFlSDRs2VFxcXLb9fn5++uyzzzRx4kQ999xzat++vcqWLStJeuqpp/THH3/kZ7kAgAKK0AQAKLQaNmyozz77TFWqVFGJEiWc7ePHj9fFixc1ZswYbd68WcHBwerTp4+z/9y5c9q8ebN8fflnEgDAlOMAgEIsNjZWDodDsbGxWr16tTZs2KBRo0Zp/vz5qlKliiQpMjJSKSkpmjhxon7++Wd99tln6tq1q06cOKELFy5YfAYAgIKA/4QGACi0QkNDtXjxYr3++usaPXq0MjIydNttt2nChAnq2LGjJCkmJkaJiYlavny5Fi1apNDQUDVv3lxdunTRqFGjtG/fPoWHh1t8JgAAK/GdJgAAAAAwweN5AAAAAGCC0AQAAAAAJghNAAAAAGCC0AQAAAAAJghNAAAAAGCC0AQAAAAAJghNAAAAAGCC0AQAAAAAJghNAAAAAGCC0AQAAAAAJghNAAAAAGCC0AQAAAAAJv4PVlWozgiWPi4AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# InvCostCE\n", + "years = ['y2020', 'y2025', 'y2030', 'y2035', 'y2040', 'y2045', 'y2050']\n", + "invCE_values = [data_results['vInvCostCE'][data_results['vInvCostCE'].sYear == year].vInvCostCE.sum() for year in years]\n", + "\n", + "# Convert years to a more readable format for plotting\n", + "years_readable = [year[1:] for year in years]\n", + "\n", + "plt.figure(figsize=(10, 5))\n", + "plt.bar(years_readable, invCE_values)\n", + "plt.title('Inv Cost CE')\n", + "plt.xlabel('Year')\n", + "plt.ylabel('Inv Cost CE [GEuro]')\n", + "plt.grid()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Total investment in ST" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1YAAAHZCAYAAACFJapPAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAABI10lEQVR4nO3deVyVZf7/8fc57AgouIBLpaLgiisu33KdMiuXSMsxNdHMzIXS1LLQ3HMUzdLUTB1zYdS0LNNMrSmrUUOn1DL3LRfAHVQW9dy/P/x5Zs6IeeAGDsjr+XjweMB1Xfd1PjfX3A1vz33dx2IYhiEAAAAAQI5ZXV0AAAAAABR2BCsAAAAAMIlgBQAAAAAmEawAAAAAwCSCFQAAAACYRLACAAAAAJMIVgAAAABgEsEKAAAAAEwiWAEAkMsMw3B1CQCAfObu6gIAAEXLjBkzNHPmTO3bty/fXvOrr77SihUr9Pvvv+vq1auqUKGCHn/8cT333HPy8/PL1dc6cOCARo4cqWXLlv3puOvXr2vJkiX67LPPdOTIEVksFlWsWFHt27dX9+7d5enpKUkKDw+/62u+/fbbeuqpp3KlfgBAzhCsAAD3LJvNpmHDhmn9+vXq1KmTunbtqmLFiumXX37R/PnztWnTJi1cuFABAQG59prr16/Xzz//fNdxI0eO1IYNG9S3b1/VqlVLNptN27dv1/Tp07Vjxw69//77kqTly5c7HNelSxd17txZTz/9tL3t/vvvz7X6AQA5Q7ACANyz5s2bpy+++EIzZ87UI488Ym9v2rSpGjVqpG7duun999/XiBEj8rWuU6dO6dNPP9XYsWP1zDPP2NubNWumoKAgTZw4Ubt27VJERITq1q172/EhISFZtgMAXIc9VgAAl/rkk09Uo0YN7dy5U126dFHt2rXVqlUrzZ8/3z7m0UcfVUxMzG3HduzYUS+99FKW8167dk0LFixQ8+bNHULVLQ0aNFBMTIyqVKlib0tNTdXbb7+thx9+WLVr11a7du20cuVKh+N+/fVX9ezZUw0aNFC9evUUHR2tX375RdJ/bnOUbt7CN2PGjCxrO3v2rAzDkM1mu62vffv2GjJkSK6+iwYAyHu8YwUAcDmbzaZXXnlF0dHReuWVV7Ry5UpNnjxZYWFhatasmTp06KC5c+fq8uXL9j1Rhw4d0t69e+8YrH777TdduHBBrVq1uuPr9u/f3/59enq6nn32WZ07d04xMTEqX768Nm3apDfffFNnz55Vv379dPnyZfXp00dNmjTRjBkzlJmZqdmzZ+v555/Xt99+q6efflqJiYlauXKlli9frpCQkCxft1q1aipbtqzefvtt7du3T61atVL9+vXl5+enoKAgvfjiiyZ+mwAAVyBYAQBczjAM9e/f375vqEGDBtq4caO+/fZbe7CaMWOGNm3apCeffFKS9MUXXyggIECtW7fOcs7Tp09LkipUqOBUDZ988on279+vZcuWqV69epJu3pp3/fp1zZo1S3/961919OhRXbhwQc8995zq168vSapcubKWL1+uK1euKCQkxB6m/uxWPU9PT82dO1fDhw9XfHy84uPjZbVaVbNmTT322GPq1q2bvL29naobAFAwcCsgAKBAuBVmpJvBIygoSFevXpUk3Xfffapfv77WrVtnH7N27Vq1bdvW/vS8/+XufvPfDrO63S4rP/30k8qXL+9QhyR16NBBGRkZ2rlzp6pWraqgoCD169dPo0aN0saNG1WqVCkNGzbsju9O3UlYWJhWr16tlStX6pVXXlHjxo114MABTZ48WVFRUTp//ny25gMAuBbBCgBQIPzvOzRWq9Xh86A6duyof/3rX7pw4YJ2796tY8eOqWPHjnecr1y5cpKkkydP3nHM+fPnlZmZKUm6dOmSSpcufduYUqVKSZJSUlJUrFgxLV26VC1atNCXX36pgQMHqmnTpho1apR9nuyqXbu2XnrpJS1cuFBbt25VTEyMDh8+rA8//DBH8wEAXINgBQAoFB577DFZLBZt2rRJ69atU/ny5dWgQYM7jq9evbpKlSqlzZs333FMbGysWrZsqczMTBUvXlxnzpy5bcyttsDAQEk3b/2bMmWKtm7dqmXLlikqKkrLly/XokWLnD6Xv/3tb2rbtu1t7T4+PhowYICqVaumgwcPOj0fAMD1CFYAgEIhICBArVq10tdff62vvvpKHTp0kMViueN4q9Wq6Ohoffvtt/rmm29u69+6dau+++47++2EkZGROnny5G2fQfX555/Lw8NDERERWr9+vZo0aaIzZ87Izc1N9erV0+jRoxUQEKBTp07ZX/duKlWqpCNHjjjc2njLlStXlJycrLCwsLvOAwAoOHh4BQCg0OjQoYNiYmJ048aNP70N8Jbo6GglJCRo0KBB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+eKaPqSlLly4ouvXbbkyJ2uTe/JifQAAAMwKCiomNzendk85t8cKAAAAAHBnBCsAAAAAMIlgBQAAAAAmEawAAAAAwCSngtXq1at14cKFvK4FAAAAAAolp4LViBEj9Mcff+R1LQAAAABQKDkVrHgiOwAAAADcmVMfEAwAhZHVapHVanF1GfcEm82QzcY/sgEAcCdOB6uVK1dq8+bNdx1nsVg0YMAAU0UBgFlWq0UlSvg6/aF++HM3bth08eJVwhUAAHfgdLBasWKFU+MIVgAKAqvVIjc3q+KW7tCJpFRXl1OoVQj219BuDWS1WghWAADcQbaCVURERF7WAgC57kRSqg6dvOTqMgAAwD2Oe2QAAAAAwCSCFQAAAACYRLACAAAAAJOc2mO1d+/evK4DAAAAAAqtbH2O1a+//qqAgADdf//9kqQLFy7oww8/1KFDhxQeHq7o6GgFBQXlSaEAAAAAUFA5dSvgtWvXNHDgQD399NNav369JCkjI0PdunXT3//+dyUlJWnlypV6+umndf78+TwtGAAAAAAKGqeC1ZIlS/T9999rxIgR6ty5syRp6dKlOnz4sGJiYrR69Wpt3LhRfn5+mjNnTp4WDAAAAAAFjVPBas2aNerdu7eee+45+61+X375pXx8fNS7d29JUrFixdSjRw998803eVctAAAAABRATgWro0ePqmHDhvafL1++rN9++0316tWTl5eXvb1ixYpKSkrK/SoBAAAAoABzKlgZhiGr9T9Df/75Z9lsNjVu3NhhXGpqqnx8fHK3QgAAAAAo4JwKVpUqVdKvv/5q//mf//ynLBaLHnroIYdx3333nSpWrJirBQIAAABAQefU49Y7dOig999/X4GBgbLZbPrkk09UvXp11axZ0z7myy+/1KpVqzR48OA8KxYAAAAACiKnglWPHj20b98+jRw5UoZhqGzZspo8ebK9/7HHHrPvw+rRo0eeFQsAAAAABZFTwcrNzU1vv/22YmJidPbsWVWrVk0eHh72/pYtW6py5cp68sknHdoBAAAAoChwKljdUrZsWZUtW/a29tdeey3XCgIAAACAwsaph1cAAAAAAO6MYAUAAAAAJhGsAAAAAMAkghUAAAAAmJTtYDVz5kwlJSVl2XfixAmNHTvWdFEAAAAAUJhkO1i9//77dwxWO3fu1Mcff5yt+S5evKhRo0apefPmql+/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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# InvCostST\n", + "# Now lets graph the investment costs for supply technologies\n", + "\n", + "# List of years\n", + "years = ['y2020', 'y2025', 'y2030', 'y2035', 'y2040', 'y2045', 'y2050']\n", + "\n", + "# Calculate investment costs for each year\n", + "invST_values = [data_results['vInvCostST'][data_results['vInvCostST'].sYear == year].vInvCostST.sum() for year in years]\n", + "\n", + "# Convert years to a more readable format for plotting\n", + "years_readable = [year[1:] for year in years]\n", + "\n", + "plt.figure(figsize=(10, 5))\n", + "plt.bar(years_readable, invST_values)\n", + "plt.title('Inv Cost ST')\n", + "plt.xlabel('Year')\n", + "plt.ylabel('Inv Cost ST [GEuro]')\n", + "plt.grid()\n", + "plt.show()\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Total installed capacity in GW by technology and year" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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EREREZGeOHgFEREREZEFUKlUUCqzithGQFqaDBkZ6VAq9Rt9z5CxjBHPEGQyOUTRMNeaWFgREREREZkxSZKQmBiL1NRkrbaPiRGhUhlm1D1DxjJGPENQKBzg5FRO62HVC8LCioiIiIjIjOUUVQ4OrrC2timyAJDJBINdETJkLGPE04ckScjISEdychwAwNm5vF7xWFgREREREZkplUqpLqocHJy02kcuFw02T5QhYxkjnr6srW0AAMnJcXB0dNWrWyAHryAiIiIiMlNKpRLAvwUAGV7OY1vU/WtFYWFFRERERGTm9L3/hwpmqMeWhRUREREREZGeeI8VEREREZEFEkUBopj3aotMZrhrJ/nFUqkkqFTmMQCFOWFhRURERERkYURRgIuLnUGLKG0plSrEx6foXFwlJiZg8+YQnDt3Fi9fvkTt2nUwevQ4eHs3BgCEh19CSEgQHj68Dze3Shg+fCTefruzev+oqEiEhAThypVwZGRkoH79hggImIhatWqrt/n555+wbdtG/PPPP6hevTrGjp2IZs1aGOS4i8LCioiIiIjIwoiiAJlMxIo94YiISiqxdqu6OWKqvw9EUdC5sJo3bzZiY19g/vzFcHUthwMHQjF58lhs374HkgRMmzYR/fv7IzBwIX799SwWLgyEi4srmjVrgYyMDEybNgFOTs5Ytmw1rK1tsG3bRkyY8DF27twHV1dXXL4chgUL5mLs2Ilo0cIX3357FNOnT8S2bXtQo0ZNIz0i/2JhRURERERkoSKiknDvaYKp0yhSRMQTXLp0ERs3bkODBl4AgEmTpuPixfP44YfvERv7ArVr18HIkWMAANWr18Dt27ewd+9ONGvWAteuXcH9+/dw+PBxvPZaRQDAJ58sRPfub+HXX39Bjx7vYffuHXjzTT/85z/9AQBjx07AH39cw9df78X06XOMfowcvIKIiLQiigLkchFyuZhvn35TMufciIgIcHZ2wfLla1CvXn31MkEQIAgCkpIScf361Txd9nx8muP69auQJAm1atXG8uVr1UUVAMhkMgBAUlISVCoV/vjjGnx8mmvEaNq0Ga5du2LEI/sXCysiIiqSKApwdlbA1dUerq72cHZWmE0BY865ERFRNkdHR7Rq1RbW1tbqZadPn0RExBO0bNka0dHRqFjRTWOfChUqIC0tDQkJCShfvgJatWqjsX7//lCk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dh4eHujXr5/eCT579gxTpkzBjh071MVbo0aNcPfuXaxbtw62trZ5hn/PKajs7OyK1aZKJSExMUW/xEuYTCbCyUmBxMRUKJUqs4lVlnIzdDzmZvpYZSW3nDi6KqzdspCbMeIxN9PHYm6lM15ZyK2o98vixDfnx62kODkptL7CpnNh9e2336JOnToFro+MjESlSpXw/vvv6xo6X9euXUNmZiYaNWqksdzb2xu//PILXn/9dURHR2usy/nbzc2t2O1mZVnGk/0qpVJlsNwNGcvQ8cw5N0PHY26mj2XoeOacm6HbLUu5lZVzhLmZPpah45lzboaOV5ZyM2R8c37czInOHRx79uxZ4PxVYWFh6Nq1q95J5VapUiUAwN9//62x/Pbt26hRowaaN2+O8PBwjYEyLly4gJo1a6J8+fIGzYWIiIiIiCg/Wl2x2rZtG1JSsrvGSZKE/fv345dffsmz3ZUrV/Lc76QvLy8v+Pj4YMaMGZg3bx4qVaqEI0eO4Pz58/jqq69QtWpVbNmyBXPmzMGIESNw/fp17NixA59++qlB8yAiIiIiIiqIVoVVeno6goODAQCCIGD//v15thFFEY6Ojvj4448NmqAoitiwYQPWrFmDWbNmISEhAe7u7tixYwe8vb0BAFu2bMHixYvRq1cvvPbaa5g+fTp69epl0DyIiIiIiIgKolVh9fHHH6sLJk9PT+zbt09d1JQEZ2dnzJs3D/Pmzct3vZeXF/bt21di+RAREREREeWm8+AVt27dMkYeREREREREFkurwmrWrFkYM2YM3njjDcyaNavQbQVBwJIlSwySHBERERERkSXQqrC6ePEihgwZov53YQRB0D8rIiIiIiIiC6JVYfXzzz/n+28iIiIiIiIqxjxWABAeHo7169er/75x4wYmTJiAP//802CJERERERERWQqdC6szZ85gyJAhOHfunHqZIAh4+PAhBgwYgLCwMIMmSEREREREZO50LqzWrVuH7t27Y+/evepl9erVw9GjR9G1a1esWrXKoAkSERERERGZO50Lq3v37uH999/Pd5CK999/n8OxExERERFRmaNzYeXo6IgHDx7ku+7Jkyews7PTOykiIiIiIiJLonNh9c4772Dt2rU4deqUxvKzZ89i7dq1eOeddwyWHBERERERkSXQarj13CZNmoQ//vgDH3/8MaysrODi4oL4+HhkZWXB29sbU6ZMMUaeREREREREZkvnwsrBwQGhoaE4c+YMwsPDkZCQAEdHRzRr1gwdOnSAKBZrBHciIiIiIiKLpXNhBQCiKMLPzw9+fn551kmSlO/AFkRERERERKVVsQqr48eP4/fff0dGRgYkSQKQXVClpKTg6tWr+OWXXwyaJBERlS2iKEAUBchk7AVBRESWQefCKjg4GMHBwXB0dERWVhasrKwgl8sRGxsLURTxn//8xxh5EhFRGSGKAlxcFZCJMlOnQkREpDWdfwo8fPgw3n//ffz+++8YOnQo/Pz88Ntvv+HAgQNwcXFB3bp1jZEnERGVEaIoQCbKEHRhG766ftTU6RAREWlF58IqKioKPXv2hCAIqFevHq5cuQIAaNiwIUaPHo39+/cbPEkiIip7niZGIvpljKnTICIi0orOhZWdnZ16cIrq1asjIiICaWlpAIB69eohIiLCsBkSERERERGZOZ0Lq0aNGuHIkSMAgJo1a0Imk+H8+fMAgHv37sHa2tqgCRIREREREZk7nQevGD16NIYNG4bExER88cUXePfddzFjxgy0bNkS586dw9tvv22MPImIiIiIiMyWzoVV8+bNceDAAfz9998AgMDAQIiiiMuXL6NLly6YOXOmwZMkIiIiIiIyZ8Wax8rT0xOenp4AABsbGyxcuNCgSREREREREVmSYhVWMTEx2LlzJ37//XckJCSgfPnyaNWqFQYNGgQnJydD50hERERERPnghOrmQ+dn4NatW+jWrRu+/PJL2Nraon79+pDJZNi4cSN69uyJf/75xxh5EhERERFRLjkTqru62sPJSWHqdMo8na9YLV26FJUrV8aWLVvw2muvqZdHRUVhxIgR+Pzzz7F27VqDJklERERERJpyT6j+ml15fOD1nqlTKtN0vmJ17do1jB8/XqOoAgA3NzcEBATgt99+M1hyRERERERUOE6obh50LqxcXV2RlJSU7zqlUglbW1u9kyIiIiIiIrIkOhdWY8eOxYoVK3D58mWN5ffv38fatWsREBBgsOSIiIiIiIgsgc73WB05cgTp6enw9/dH1apV4ebmhri4ODx8+BAqlQqbNm3Cpk2bAACCIOCnn34yeNJEZU3OiD+5qVQSVCrJRBkRERERUW46F1ZVq1ZF1apVNZa98cYb8PLyMlhSRPQvQRDg4moHmShApZLUBZZSqUJ8fAqL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iIjKhKeJkaZOgcgsWFxh9ffff2v87eXlhX379pkoGyIiIiIiIjPvCkhERERERGQJWFgRERERERHpiYUVERERERGRnlhYERERERER6YmFFRERERERkZ4sblRAIiIiIiIqPpks+9qKSiVBpZJMnE3pwcKKiIiIiKgMsHe0gVKphJOTAgCQlaVEQkIqiysDYWFFRERERFQG2CqsIJPJEBAQAAAIDg6GKAosrAyEhRURERERURly584dU6dQKnHwCiIiIiIiIj2xsCIiIiIiItITuwISEZVyoihAFAX1KFBERERkeCysiIhKMVEU4OJix6KKiIjIyPhJS6QjURQgl4uQy0WIomDqdIgKlXOlasWecOw8fsPU6RAREZVavGJFpANRFODqooAokwEAVEol4uJTTZwVUdEiopIAicPpEpHxyWQiJ56lMolXrIh0IIoCRJkMt1etwe1VayDKZLxqRUREZZ6LrRMkSQUAcHJSwNXVjp+PVObwihVRMaQ8iTB1CkRERGbDzkoBQRDx4PpeAEBNrwGceJbKHBZWRERERGQQqS+jTZ0CkcmwKyAREREREZGeWFgRERERERHpiYUVERERERGRnniPFRERmYwoCuq5toiIiCwZCysiPfELIVHxiKIAFxc7voaIiKhU4KcZUTFZubhAJang5KSAk5PC1OkQWZycK1Ur9oRj5/Ebpk6HiIhILyysiIpJ7mAPURARdGEbvrp+1NTpEFmsiKgkRMemmDoNIiIivbArIJEWCrsP5GliJCSJEyASERERlWUsrIiKwPtAiIiIiKgo/KZIVATeB0JEREREReEVKyItRUQlAezyR0RERET5YGFFRERkIXLu9wQAlUqCSsUfe4iIzAULKyIiIgsgigKcnRWQy2UAgKwsJRISUllcERGZCRZWREREFkAUBcjlMgQEBAAAgoODIYoCCysiIjPBwoqIiMiC3Llzx9QpEBFRPjgqIBEREREZnEwmqu8JJCoLWFgRERERkcHIrR2hkiQ4OSng4mrP4orKDBZWRERERGQwcitbiIKAb+88gyzXSJZEpR0LKyIiIiIyuBepGaZOgahEWURhFR8fj8DAQLz55pto2rQpPvjgA4SFhanXnz9/Hr1794a3tze6dOmCY8eOmTBbIiIiIiop2SNmioX+J4rZX3llssK3y96WV9ioeCxiVMDJkyfj+fPnWLVq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2LH8/PPPmM1mkpOTb9t30qRJRmXB119/neHDh/Pss89y7tw5rFYr69atAyAyMpKwsDAAkpKSGDFiBAkJCXTv3t3p/ObOnYvVaqWqqorY2FgiIiLIycnBZrMRFxeHyWQiNjYWHx8fKioqGD9+PKNHj2bixInYbDb8/f2NcCYiIveGgpWIiHSa9evXs3z5cp544gn++ecfrFYrc+bMITMz01iJ6t+/P7t27WL8+PH4+vrS3NzM4MGD2bRpE9OmTbtnc3vrrbdITk5myJAhOBwOzGYzsbGx7N69+6bth/+fh4cHmZmZrFq1iieffBKbzYbFYuHFF18kLy/vpjNUW7duJS4uDrPZjLe3NwsXLmTWrFnAf859tcVisZCbm8tzzz1Hz549aWxsJDg4mLS0NBISEoCWs1q5ublMnToVq9XK1atX6du3L9OmTeOTTz657Tk1ERHpGCaH6q+KiIjccydPniQvLw+LxUJ0dDRDhw7l+vXrLF68mG+//ZaZM2eyfv36rp6miIjcJQUrERGRTnDx4kUmTZpEQ0ODUc69rq6OxsZGPDw8yM3NZdiwYV09TRERuUvaCigiItIJ+vTpQ3Z2NqNHj6ZHjx7U1NTg6enJiBEjyMjIUKgSEbnPacVKRERERETERVqxEhERERERcZGClYiIiIiIiIsUrERERERERFykYCUiIiIiIuIiBSsREREREREXKViJiIiIiIi4SMFKRERERETERQpWIiIiIiIiLvo/nSUTjdtZE68AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Define a function to filter and process the data\n", + "def process_data(year):\n", + " data = data_results['vCETotCap'][data_results['vCETotCap'].sYear == year]\n", + " data = data[~data.sCE.str.startswith(('sPE2TE', 'sTE2TE'))]\n", + " data = data.drop(columns=['sYear']).set_index('sCE')\n", + " return data\n", + "\n", + "# Process data for each year\n", + "years = ['y2020', 'y2025', 'y2030', 'y2035', 'y2040', 'y2045', 'y2050']\n", + "data_by_year = {year: process_data(year) for year in years}\n", + "\n", + "# Create a figure and a set of subplots\n", + "fig, ax = plt.subplots(1, 1, figsize=(10, 5))\n", + "\n", + "# Set the bar width\n", + "barWidth = 0.15\n", + "\n", + "# Set the position of the bars on the x-axis\n", + "r = np.arange(len(data_by_year['y2020']))\n", + "positions = [r + i * barWidth for i in range(len(years))]\n", + "\n", + "# Define colors for each year\n", + "colors = ['b', 'r', 'g', 'y', 'c', 'm', 'k']\n", + "\n", + "# Make the plot\n", + "for i, year in enumerate(years):\n", + " plt.bar(positions[i], data_by_year[year].vCETotCap, color=colors[i], width=barWidth, label=year[1:])\n", + "\n", + "# Add xticks on the middle of the group bars\n", + "plt.xlabel('Technologies', fontweight='bold')\n", + "plt.xticks([r + barWidth * (len(years) - 1) / 2 for r in range(len(data_by_year['y2020']))], data_by_year['y2020'].index, rotation=90)\n", + "plt.ylabel('Capacity [GW]')\n", + "plt.title('Total Capacity by Technology and Year')\n", + "# Create legend & Show graphic\n", + "plt.legend()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Decommisioned capacity per technology and year" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA00AAAJvCAYAAACnEDqlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdd1wT9xsH8M9d2BvFrXWggBMVB46qWOvW1tE6cGuduBU3WletoiIibq2zUnetq9Vq3VZx14VbrICIMpSV5H5/UPIzgiHBQAJ+3q+XL8nd9557Lrkk9+R79z1BkiQJRERERERElCnR0AkQEREREREZMxZNREREREREGrBoIiIiIiIi0oBFExERERERkQYsmoiIiIiIiDRg0URERERERKQBiyYiIiIiIiINWDQRERERERFpwKKJiIg+GbyfOxERZQeLJiJS6dmzJ1xdXVX/3NzcUKNGDXTs2BEbN26EXC43dIq5Ijw8HK6urti1a5feYjZt2hQTJ07UWzx90Dan5ORk/PTTT+jUqRM8PDxQp04ddO3aFXv27DHqImTXrl1wdXVFeHg4ACAsLAzdunX76Liurq5YunTpR8d51/vvvcz+6WP/OX/+PFxdXXH+/Hk9ZJ21iRMnomnTprmyLkN7f397V3JyMlq1aoU6deogOjo60+UXLlwIV1dXnDhxIqdTJaJsMDF0AkRkXCpVqoTp06cDABQKBWJjY3HixAn88MMPuHjxIgICAiCK+fv3lsKFCyMkJASfffaZ3mIGBQXBxsZGb/FyS3R0NAYMGIDnz5+jZ8+eqFatGpRKJY4dO4aJEyfi4sWLmDVrFgRBMHSqGTRp0gQhISEoXLgwAODQoUO4fPmygbPK3PTp05GQkKB6/P3336umpytQoECu50X6YW5ujrlz56J79+6YOXMmAgMD1eb/888/WLduHbp06YJGjRoZKEsi0oRFExGpsbGxQfXq1dWmNW3aFOXKlcOcOXPw22+/oX379oZJLpeYmZlleA4+VqVKlfQaL7dMmDABERERCAkJQZkyZVTTmzRpguLFi2PRokXw8vLCF198YbgkP6BAgQJ5ptAoX7682uP0Alvf+yEZTo0aNdC7d2+sX78eR44cQbNmzQAAcrkckydPRvHixY2uN5qI/i9//1xMRHrTo0cPFClSBNu2bVObvn37drRp0wZVqlRBkyZNsHTpUigUCrU2f/31F7p27Yrq1aujYcOG8PPzQ1xcnGr+o0ePMGLECDRo0ADVq1dHz549ERoaqpqffrrcoUOHMHToUFSvXh3169dHcHAwEhISMHnyZHh4eKB+/fpYsGCB6pSxj10u/fQ8pVKJxYsXo2nTpqhSpQqaNm2KhQsXIjU1VZVjejFZrVo1eHp6Yty4cYiMjFTNf/9UuPj4ePzwww9o1qwZqlatirZt22LHjh1qz1vTpk0RGBiIH3/8EfXr10e1atXQv39/PHr0SK3dxYsX0aNHD7i7u6NOnTqYMGECYmJi1Nrcvn0bffv2RY0aNeDl5YVff/1V8wsO4NatWzh16hT69++vVjCl69OnD7y9vWFlZaWaduHCBfTv3x+1a9dWPVdLly6FUqlUe27379+PwYMHw93dHU2aNMGyZctUbQAgKSkJCxcuRPPmzVGlShXUrFkTffv2xa1bt9Ry0LRvvXu61NKlSxEUFATg/6fXjRgxAo0aNVJbLwBMmTIFLVq00PjcJCQkYNy4cahRowbq1auH2bNnIzExEQCwZcsWuLq64uHDh2rL7N27FxUrVsTz5881xtbkyJEj6NixI6pWrYoGDRpg9uzZePv2rVqbK1euoF+/fqhZsyY8PT0xZswYtX0RAB48eID+/fvD3d0dDRo0gL+/v9rpt66urtiyZQumTJmCOnXqoEaNGhg5cmSGU8sOHDiAjh07okaNGmjQoAH8/PwQGxv7wfwVCgW2bNmCdu3aoVq1amjSpAn8/f2RnJys1m737t1o3bo1qlativbt2+Ps2bOoVKkSdu3ahdevX6Nq1apYtGiR2jKJiYnw8PDA8uXLP7h+bffPgwcPYsSIEahRowbq1KmDqVOnqj3PSqUSwcHBaNKkCdzd3TF06FCN251u1KhRKFOmDL7//ntVz+LatWtx9+5dzJs3T/Ve0uY9re22rF+/Hi1btoS7uzt27tyZZY5ElDkWTUSkFVEUUa9ePVy7dk11cLVy5UpMmzYN9erVw4oVK+Dt7Y3Vq1dj2rRpquWOHTuGQYMGoWDBgggICMC4ceNw5MgRjB49GgBw7949dOzYEeHh4Zg6dSr8/f0hCAJ69+6Nv//+Wy2HqVOnwsXFBcuXL0e9evWwZMkSdO7cGRYWFggKCkLz5s2xZs0aHDp0SC/LpVu9ejV+/vlnDBs2DOvWrUO3bt2wdu1a1cFZaGgofH190bx5c6xevRqTJk3CuXPnMHbs2EzjJSUloXv37ti3bx8GDBiA4OBgeHh4YMqUKVixYoVa240bN+LBgwf44YcfMHv2bNy4cQMTJkxQzb9w4QL69OkDCwsLBAQEYPLkyfj777/Rq1cvJCUlAQAiIyPRo0cPxMfHY8GCBRg5ciT8/f0zHEi/7+TJkwDwwWtSzM3N4efnh3r16gFIK8z69OkDBwcHLF68GMuXL0etWrUQFBSEgwcPqi07Y8YM2NjYYOnSpfjqq68QFBSEhQsXqub7+vpi586dGDhwINatW4dJkyYhLCwMY8eOVRW3We1b7/rmm2/QuXNnAEBISIjqcWRkpNr1PUlJSTh06BA6dOig8bnZtGkT3rx5g4CAAAwaNAjbt2/HuHHjAADt2rWDubk59u7dq7bMnj17UK9ePRQrVkxj7A/Zt28fhg0bhnLlymHZsmXw8fHBr7/+iqFDh6qek5s3b6JHjx5ITk7G/Pnz8f333+PGjRvo37+/WlH0ww8/wMPDAytWrECrVq2wevXqDD+ILF68GEqlEosWLYKvry+OHTuGuXPnquYHBwdjzJgxqF69OgIDAzFs2DAcPnwYPXv2VO177/Pz81P9WLB8+XJ4e3tj8+bNatuwZ88eTJw4ETVr1kRwcDBatGiBoUOHqn6McXBwQLNmzbBv3z61a+r++OMPvH37Fl9//XWm69Zl/5w+fTpKlCiB4OBg9O/fHzt27FArxhYsWIBly5ahc+fOCAoKgoODg9r++yEWFhaYM2cOXrx4gaCgIISHhyM4OBj9+vWDh4cHAO3e07psy9KlS/Hdd99h/vz5aNCgQZY5EtEHSERE/+nRo4fUo0ePD86fP3++5OLiIr148UKKi4uTqlWrJvn5+am1+eWXXyQXFxfp7t27kiRJUocOHaSvv/5aUiqVqjb79++XmjdvLr148UIaOXKkVLduXSk+Pl41PzU1VWrRooXUqVMnSZIk6enTp5KLi4s0atQoVZsXL15ILi4uUvfu3VXTlEqlVLNmTWn27Nl6WW7nzp2SJElSv379pL59+6pt56ZNm6Q9e/ZIkiRJK1eulGrUqCElJyer5h8/flxaunSparu9vLykCRMmSJIkSVu2bJFcXFykS5cuqcWcPHmyVLVqVenVq1eqZby8vCS5XK5qs3TpUsnFxUWKiYmRJEmSunTpIrVt21atzYMHD6SKFStKmzdvliRJkubNmydVr15devnyparNlStXJBcXF1VOmZkxY4bk4uIiJSUlfbDNu3bv3i0NGDBAUigUqmkKhULy8PCQpk2bJknS/5/b3r17qy07e/ZsqXLlylJ8fLyUnJws9evXT9q/f79am3Xr1kkuLi5SVFSUJElZ71s7d+6UXFxcpKdPn0qSJEmBgYGSi4uLWm6NGjWSfH19VdN+/fVXyc3NTXr+/PkHt9PFxUVq27at2nb+9NNPkouLi3Tnzh1JkiRpzJgxkpeXlyq358+fS25ubtK+ffuyfiKljO9FpVIpNWrUSOrfv79auzNnzkguLi7SsWPHJEmSpOHDh0sNGjRQe80uXbokeXl5STdv3pTOnTsnubi4SAsWLFCL3bhxY2nYsGFq29itWze1dU2cOFGqXr26JEmS9Pr1a6lKlSqq1zXdhQsXJBcXF9W+N2HCBMnLy0uSJEkKCwuTXFxcpJUrV6ots2fPHsnFxUU6fvy4JEmS1KRJE2nQoEFqbVauXKn2njx58qTk4uIinT17VtWmb9++Ur9+/TJ9PiVJt/1z3Lhxasv27NlTatu2rSRJkhQbGytVrlxZ7TmUJEnq37+/2v6myaxZs6TKlSur3r/vfnZo857WZVsmT56cZT5ElDX2NBGR1qT/ftUVBAGXL19GUlISmjZtCrlcrvqX3itx+vRpJCUl4ebNm2jWrJnaQAGtW7fG4cOH4eTkhL///hteXl5qgySYmJigTZs2uHHjBt68eaOaXqNGDdXfTk5OAIBq1aqppgmCAHt7e8THx6vlnd3l0tWtWxenT59G9+7dsWbNGty7dw89evTAV199BQCoXbs2EhMT0bZtWyxcuBAXL15Ew4YN4ePjk+kACX///TdKlCihlhcAtG/fHsnJybh69apqWtWqVSGTyVSPixYtCiDtVKTExERcvXoVjRs3hiRJqtegVKlScHZ2xunTpwGk9YRVr15d7foed3d3FC9ePNPtTZe+3vdPt/yQr7/+GqtXr0Zqaipu376Nw4cPIzAwEAqFQu1UxvS272rRogVSU1Nx+fJlmJmZYe3atWjdujUiIyNx7tw5bNu2DceOHQMApKSkaLVvZUUURXTo0AG///676tS63bt3o379+qrn+UNatmypNiBK8+bNAaT1EgBA586d8ezZM1y8eBFAWu+JtbU1vvzyyyzzysyDBw8QERGR4f1Wu3Zt2NjYqL3WjRo1grm5uWrZGjVq4M8//0TFihVV02rVqqX6WxAElChRQu2UWSDj9VRFixZVPU9XrlxBSkoK2rZtq9amVq1aKFGiRIZeYgCqaW3atFGb3qZNG8hkMpw/fx6PHz/Gv//+i5YtW2Zo86769eujePHiqt68iIgInD17VmMPoS77Z2bbnn563pUrV5CamgovLy+1Nq1atfrgut83duxYFC1aFDdu3MCCBQtgZmYGAFq/p3XZlndfdyLKPg4EQURai4yMhIWFBRwcHPD69WsAwMCBAzNtGxUVhdjYWEiShIIFC34wZmxsbKYHuE5OTpAkSW1EscxGn3v3epoPye5y6QYMGABra2vs3LkT/v7+WLBgASpUqICpU6fC09MTNWrUwKpVq/DTTz9h/fr1WLVqFZycnDB48GD07NkzQ7zY2FgUKlQow/T05+Hdg1dLS0u1NukH6kqlEnFxcVAqlVi9ejVWr16dIV76gXNsbCxKliyZYX5mObyrRIkSAIB///03w0AF6SIjI1G4cGEIgoCkpCTMmjULe/fuhVwuR8mSJVGjRg2YmJhkGJq8SJEiao/TC7r060JOnjyJuXPn4sGDB7C2toabm5vqNZMkSat9SxudOnXCihUr8Pvvv8PT0xNnz56Fv79/lsu9/9yl55H+2nl6eqJkyZLYs2cPateujT179qB169ZqxYwu0t9v33//vWpkvXdFRUWp2mnznGS2X73/Gmlqk/46fei9m9kPEOnLvP/cmZiYwNHREfHx8arrdt7fhvfXI4oiOnbsiPXr12P69OnYu3cvbGxsNBaluuyf2my7o6OjWpus3k/vx69Vqxb+/vtvuLm5qaZr+57WZVt0+awjog9j0UREWpHL5Th//jxq1qwJmUwGOzs7AIC/v3+mgwQ4OTnBxsYGgiBkuIA5OTkZ586dg7u7O+zt7TO9b8mLFy8ApB2YpB8QGoooivD29oa3tzdevnyJv/76CytWrMDw4cNx+vRpmJmZ4fPPP8fnn3+OxMREnDt3Dhs3bsTs2bPh7u6u1qsFAPb29nj8+HGG9by7zdqwtraGIAjo06dPhl/igf8f+Dk6Omb6HKcfiH9Iw4YNAaQNtpBZ0SSXy/HVV1+prj2ZM2cODh8+jICAANSvX191sJZ+zdO7Xr16pfb45cuXANIOlp88eYJhw4ahWbNmWLlyJUqVKgVBELBlyxbVdVba7FvaKFWqFOrUqYODBw/i9evXsLGxUY1qpsn7z136a5d+sC8IAjp06IBNmzahW7duePjwIX788UetcspM+vvN19cXderUyTDf3t4eAGBra5vhOQHSXkN99jikry86OhrlypVTm/fixQuUKlXqg8u8ePFCVZADQGpqKl69egVHR0dVD1/6/pDu/ccA0LFjRyxbtgwnTpzAwYMHsyxKddk/NUl/f758+VJt27N6P2lD2/e0vraFiLTH0/OISCshISF48eKF6uag7u7uMDU1RWRkJKpWrar6Z2JigkWLFiE8PBzW1taoWLGi6rSqdCdOnMDAgQMRFRWF2rVr49ixY2o9SgqFAvv370fVqlVVp60YUteuXTF79mwAaQfFHTt2hLe3N+Li4pCQkIAff/wRnTp1giRJsLS0hJeXl2qwhn///TdDvNq1a+PZs2cZ7hn066+/wtTUNEOR9SE2NjaoVKkSHjx4oPYaVKhQAUuXLlUNcODp6YnLly+rDfxw7949PH36VGP8ChUqoFGjRli9enWmbVeuXIlXr16phqAPDQ1F3bp10axZM9VB3I0bNxATE5NhhLojR46oPT58+DAsLS3h7u6OGzduIDk5GQMHDsRnn32mOv0uvWCSJEmrfet9H7q/WOfOnXHmzBn89ttvWvcGvX8D0v3790MQBLWCpmPHjoiLi8OPP/4IZ2dnrQu5zJQrVw4FCxZEeHi42mtdpEgRLFy4EDdv3gSQdnrc6dOnkZKSolr25s2bGDhwIP75559sr/997u7uMDMzw2+//aY2/eLFi/j3339Rs2bNDMukPzf79+9Xm75//34oFAp4eHigaNGi+Oyzz/DHH3+otfn9998zxCtRogTq1auHjRs34tatW+jYsaPGnHXZPzWpUaMGLCwsMgwc8/6+mB3avqf1tS1EpD32NBGRmoSEBFy5cgVA2ilgr169wqlTpxASEoL27durrt1wdHTEgAEDsGTJEiQkJKBu3bqIjIzEkiVLIAiC6pSTESNGYMiQIRgzZgy+/vprREdHY9GiRWjWrBlcXFzg4+ODEydOoFevXhg4cCBMTU2xefNmPH36FGvWrDHU06Cmdu3aWLduHZycnFCjRg1ERkZi/fr1qFOnDgoUKABPT0+sX78eEydORPv27ZGamoo1a9bA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1K/fEMnJSRmuPTIzMwcApKQkq00fOnQEVq78CVWqVMWoUUMRGRkBAHjw4D5SUlJQuXJVLFwYiN69+2Pfvj348cfZubNRRERERES5gEXTJ+DkyeMYPXoYKleuAj+/tILG3Nwcqampau3SiyULC0u16RUquKJy5SqYOXMeJAk4cGAfAGD8+MnYs+cgOnbsjHLlyqNFi9YYOXIsDh8+gJiYlzm+XUREREREuYFFUz63c2cIpkzxRYMGn2P+/ACYm6f1JhUuXATR0S/U2kZHR8PS0go2NjaIjIzAsWNH1OZbWlqiePESePEibfRAExMT2NnZqbUpW9YZABAVlXsjDBIRERER5SQWTfnY7t07sHjxAnTs+C1mzJirdjpejRo1cflyqFr70NALqFrVHaIo4t69MEybNhFPnjxSzY+Pj8eTJ49Rpkw5AICPz0DMnfu9Wozbt2/C1NQUpUqVyrkNIyIiIiLKRRxyXEeW1oXzxPqePHmMJUv80aiRF3r27KN2upy5uQW++aYrevXqhuXLl6J163Y4c+YUjh07gkWLggAAdep4onx5F8yaNR1jx06EIAgIDg6Evb0D2rZtDwDw8voCgYGLUKVKVXh41MHt2zcRHLwEXbv2gLW1zcdvPBERERGREWDRpCWlUoJSqUTZat0NsG4llEpJp2WOHz8KuVyOEyeO4cSJY2rzWrVqi+nTZ2LevEVYvjwQ27f/jGLFisPPbzY8PGoDSLtBrb9/IIKCFmPcuOFISUlFnTqeCApaCSsrawBAp05dIAgifvnlZwQE+KNgQSd8+2139OjRRy/bTURERERkDFg0aUmplPDq1VuIomCQdeu63l69+qFXr34a23h61oenZ/0PzndycsKMGXM0xujY8Rt8+20XyOVKnfIjIiIiIsorWDTpIK23SbceH30xRLFGREREREQcCIKIiIiIiEgjFk1EREREREQasGgiIiIiIiLSgEUTERERERGRBiyaiIiIiIiINGDRREREREREpAGLJiIiIiIiIg14nyYdiKJgsJvbEhERERGRYbBo0pIoCnBwtIbMAEWTQikhPi4x19dLREREREQsmrQmigJkooA1Vx7ieUJSrq23mI0FBlQvm60erri4WKxcuQxnzpzCmzdv4OxcHoMHD4e7e3UAQGjoBQQHB+LRowcoUqQo+vUbiGbNWmQa6+rVyxg+fBACAoJR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tm3b4OvrmyPJ5gZBEGBlZQNLS2solUoolQpDpwSZTIC9vRViY9/qpXdIn/F0iSWTmbCHiYiIiIjyHK2Kpr1796JLly4ZCqZ3WVhYoFOnTjh69KjekjMkQRAgk8n+u87JsExMRFhYWCAxUQG5/ON7h/QZT9+5EREREREZG61+9r937x4aNWqUZbuaNWviyZMnH50UERERERGRsdCqp0kul8PS0lJtmkwmw++//46iRYuqTePpV0RERERElJ9oVeEUKVIEDx8+zDD9s88+U7tn0927d1G8eHH9ZUdERERERGRgWhVNDRs2REhIiMYR0lJTU7Fjxw54eXnpLTkiIiIiIiJD06po8vb2xv379zFq1Ci8evUqw/y3b99iwoQJeP78Obp166b3JImIiIiIiAxFq2uaypUrh7lz52Ly5Mn44osvUK9ePZQpUwYA8OzZM5w6dQpyuRzz589HsWLFcjJfIiIiIiKiXKVV0QQArVu3hpubG1avXo0///xTNbS4paUlmjZtikGDBsHFxSXHEiUiIiIiIjIErYsmIK3H6YcffgAAxMXFQalUwsHBISfyIiIiIiIiMgo6XdP0Ljs7O40F0/379+Ht7f1RyRERERERERmaVkVTaGgo3rx5o1PghIQEXLp0KVtJERERERERGQutT8/r0qVLTuZBRERERERklLQqmnx8fHI6DyIiIiIiIqPEoomIiIiIiEgDra5pIiIiIiIi+lSxaCIiIiIiItKARRMREREREZEGLJqIiIiIiIg00Llo+u2335CSkpITuRARERERERkdnYsmX19fNGjQADNmzMC1a9dyIiciIiIiIiKjoXPR9Oeff6Jfv344d+4cunTpgtatW2Pt2rV48eJFTuRHRERERERkUDoXTUWLFsWQIUNw6NAhbNmyBbVq1cLq1avh5eWFwYMH4/fff4dcLs+JXImI6BMhigJMTETIZLz0loiIDE+rm9t+SM2aNVGzZk188803mD9/Po4fP47jx4/DyckJvXv3Rr9+/SCTyfSVKxERfQJEUYCDgxULJiIiMhrZLpqePXuGvXv3Yu/evXjy5Ak+++wzjBkzBk2aNMHx48exbNky3Lt3Dz/++KM+8yUionxOFAXIZCJ2bbkMB0dLNG3tZuiUiIjoE6dz0bR9+3bs3bsXly5dgrm5OVq2bIk5c+agVq1aqjYuLi549eoVtm3bxqKJiIiyJToyHpIkGToNIiIi3YumadOmwd3dHTNmzEDr1q1hY2OTaTtXV1d06dLloxMkIiIiIiIyJJ2Lpt9++w3ly5f/4PyIiAgULVoUX3/99cfkRUREREREZBR0vsq2Xbt2H7w/08WLF9GqVatsJ7Ny5Ur07NlTbdrUqVPh6uqq9q9p06bZXgcREREREZEutOppWrduHd6+fQsAkCQJ27dvx4kTJzK0u3z5MszMzLKVyJYtWxAQEKB2bRQA3LlzB4MHD0aPHj1U0zgiHxERERER5Ratiqbk5GQEBQUBAARBwPbt2zO0EUURtra2GDJkiE4JREZGYvr06Th//jzKlCmjNk+SJNy7dw8DBw5EoUKFdIpLRERERESkD1oVTUOGDFEVQ25ubggJCYG7u7teEvjnn39gamqKX3/9FcuWLcOzZ89U8548eYK3b9+iXLlyelkXERERERGRrnQeCOL27dt6TaBp06YfvEbp7t27AIBNmzbhxIkTEEURjRo1wujRo2Fra/tR6zUxyTs3TUy/waO+bvSoz3jMzTjiMTfDx9J3vJzOLau4muYbc266xMlObsYUj7kZPpa+4xlzbvqOx9wyb5Pd2NltY8zPm7HRqmiaNGkShg4dilKlSmHSpEka2wqCgLlz5+olubt370IURRQuXBgrVqzAkydPMH/+fISFhWHDhg0Qxey9KKIowNHRWi855iY7O0ujjcfcjCMeczN8LH3HM1Ru2rQz5tx0aZfbsfQdj7kZPpa+4xlzbvqOx9xyPmZuf57nxHYaA62KpvPnz6N3796qvzURBOHjs/rPkCFD0L17dzg6OgJIu2luoUKF8O233+L69evZPkVQqZQQF/dWb3nmNJlMhJ2dJeLiEqFQKI0qHnMzjnjMzfCx8lpu6Y8/RNN6jTk3fef3Ke8jxhKLueXPeMwt8za6iotLBKC5UMmtz3N9P2+5xc7OUqveMa2Kpj///DPTv3OaKIqqgildhQoVAKTdD+pjrquSy/POi5lOoVDqNW99xmNuxhGPuRk+lr7jGSo3bdoZc266tNMG9xHDx9J3POZmHPGY28fH1Md6jfl5MxbZOr8tNDQUy5YtUz2+efMmRo4ciRs3bugtMQDw9fVFnz591KZdv34dADTeYJeIiIiIiEhfdC6a/vrrL/Tu3RunTp1STRMEAY8ePUL37t1x8eJFvSXXokULnD17FkFBQXjy5An++usvTJ48GW3btoWzs7Pe1kNERERERPQhOhdNS5cuRZs2bbB161bVtIoVK2Lv3r1o1aoVFi1apLfkvvjiCwQEBODo0aNo164dpkyZgubNm+ttoAkiIiIiIqKs6Dzk+P379zF27NhMB3z4+uuvMWzYsGwnM2/evAzTWrVqhVatWmU7JhERERER0cfQuafJ1tYWDx8+zHTe06dPYWVl9dFJERERERERGQudi6Yvv/wSS5YswbFjx9Smnzx5EkuWLMGXX36pt+SIiIiIiIgMTefT80aPHo3r169jyJAhMDU1hYODA16/fg25XA53d3eMHTs2J/IkIiIiIiIyCJ2LJhsbG2zbtg1//fUXQkNDERsbC1tbW9SqVQtNmjSBKGZrFHMiIiIiIiKjpHPRBKTddNbLywteXl4Z5kmSlOkgEURERERERHlRtoqmAwcO4O+//0ZKSgokSQKQViy9ffsWV65cwYkTJ/SaJBERERERkaHoXDQFBQUhKCgItra2kMvlMDU1hYmJCWJiYiCKIr755pucyJOIiIiIiMggdL4Aaffu3fj666/x999/o0+fPvDy8sKZM2ewY8cOODg4oEKFCjmRJxERERERkUHoXDRFRkaiXbt2EAQBFStWxOXLlwEAVapUweDBg7F9+3a9J0lERERERGQoOhdNVlZWqoEeSpcujfDwcCQlJQEAKlasiPDwcP1mSEREREREZEA6F01Vq1bFnj17AABly5aFTCbD2bNnAQD379+HmZmZXhMkIiIiIiIyJJ0Hghg8eDD69u2LuLg4rFixAu3bt8eECRNQt25dnDp1Cs2aNcuJPImIiIiIiAxC56Kpdu3a2LFjB+7cuQMA8PPzgyiKuHTpElq2bImJEyfqPUkiIiIiIiJDydZ9mtzc3ODm5gYAMDc3x6xZs/SaFBERERERkbHIVtEUHR2NjRs34u+//0ZsbCwKFiyIevXqoWfPnrCzs9N3jkRERERERAaj80AQt2/fRuvWrbFhwwZYWFigUqVKkMlkWLlyJdq1a4d///03J/IkIiIiIiIyCJ17mubNm4dixYphzZo1KFSokGp6ZGQkBgwYgB9//BFLlizRa5JERERERESGonNP09WrVzFixAi1ggkAihQpAh8fH5w5c0ZvyRERERERERmazkWTo6Mj4uPjM52nUChgYWHx0UkRERER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0dSpUyckJCRgypQpuHfvHnbt2oWffvoJgwYNMnRqRERERET0iTDqoqlgwYJYs2YNHj58iA4dOiAoKAi+vr7o0KGDoVMjIiIiIqJPhFENBDFv3rwM06pVq4aQkBADZENERERERGTkPU1ERERERESGxqKJiIiIiIhIAxZNREREREREGrBoIiIiIiIi0oBFExERERERkQYsmoiIiIiIiDRg0URERERERKQBiyYiIiIiIiINWDQRERERERFpwKKJiIiIiIhIAxZNREREREREGrBoIiIiIiIi0oBFExERERERkQYsmoiIiIiIiDRg0URERERERKQBiyYiIiIiIiINWDQRERERERFpwKKJiIiIiIhIAxZNREREREREGpgYOgEiIiIiMhxRFCCKQpbtZDLxv/YiTLI4glQqJSiVkj7SIzIKLJqIiIiIPlGiKMDBwUpVEEkKJYT//lYqlRDF/6ZLSghC2t+2dhYQBeG/NpKq4FIoFJDJZAAAuVyB2NhEFk6Ub/D0PCIiIqJPlCgKkMlE+G8JxcYDNyHIRNxdFIDHm7dAFEUEnluHn6/thSCIeHhtK56FHYQoCFhz5SF233kGURSwa8tl/HngNmQyGXx8fODj4wMTE5lWvVdEeQV7moiIiIg+ceGR8YCU1iv09mk4pP/+fhYXofo78U0UJKT9/TwhKb05oiPjVW3CwsJyOXOi3MGeJiIiIiIiIg1YNBEREREREWnAoomIiIiIiEgDFk1EREREREQasGgiIiIiIiLSgKPnERHlcdrcmDL9HixERESkOxZNRER5mDY3pnz3ppRERESkO36LEhHlYVndmPLo/VNqN6UkIiIi3bGniYgoH/jQjSlfJcUBUL8pJREREemGPU1EREREREQasGgiIiIiIiLSgEUTERERERGRBiyaiIiIiIiINGDRREREREREpAGLJiIiIiIiIg1YNBEREREREWnAoomIiIiIiEgDFk1EREREREQasGgiIiIiIiLSgEUTERERERGRBiyaiIiIiIiINGDRREREREREpAGLJiIiIiIiIg1YNBEREREREWnAoomIiIiIiEgDFk1EREREREQasGgiIiIiIiLSwMTQCWgjMjISjRo1yjD9hx9+QMeOHQ2QERERERERfSryRNF0+/ZtmJub48iRIxAEQTXd1tbWgFlRfiKKAkRRyKKNqPrf5L13jkzGTlsi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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Decommissioned capacity by technology and year\n", + "years = ['y2020', 'y2025', 'y2030', 'y2035', 'y2040', 'y2045', 'y2050']\n", + "filtered_data = {}\n", + "\n", + "# Filter and process the data for each year\n", + "for year in years:\n", + " data = data_results['vCEDecCap'][data_results['vCEDecCap'].sYear == year]\n", + " data = data[~data.sCE.str.startswith(('sPE2TE', 'sTE2TE'))]\n", + " data = data.drop(columns=['sYear']).set_index('sCE')\n", + " filtered_data[year] = data\n", + "\n", + "# Create a figure and a set of subplots\n", + "fig, ax = plt.subplots(1, 1, figsize=(10, 5))\n", + "\n", + "# Set the bar width\n", + "barWidth = 0.15\n", + "\n", + "# Set the position of the bars on the x-axis\n", + "positions = [np.arange(len(filtered_data['y2020'])) + i * barWidth for i in range(len(years))]\n", + "\n", + "# Define colors for each year\n", + "colors = ['b', 'r', 'g', 'y', 'c', 'm', 'k']\n", + "\n", + "# Make the plot\n", + "for i, year in enumerate(years):\n", + " plt.bar(positions[i], filtered_data[year].vCEDecCap, color=colors[i], width=barWidth, label=year[1:])\n", + "\n", + "# Add xticks on the middle of the group bars\n", + "plt.xlabel('Technologies', fontweight='bold')\n", + "plt.xticks([r + barWidth * (len(years) - 1) / 2 for r in range(len(filtered_data['y2020']))], filtered_data['y2020'].index, rotation=90)\n", + "plt.ylabel('Capacity [GW]')\n", + "plt.title('Decommissioned Capacity by Technology and Year')\n", + "# Create legend & Show graphic\n", + "plt.legend()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "New capacity by year and technology" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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Fk1ERERERERqsGgiIiIiIiJSg0UTERERERGRGloXTb/88guSk5NzIxciIiIiIiKDo3XRNG3aNDRu3BheXl64fft2buRERERERERkMLQumn7//XcMHToUly5dQq9eveDh4YENGzbgzZs3uZEfERERERGRXmldNJUpUwajR4/GsWPHsH37dtStWxfr1q1Dy5YtMWrUKJw4cQKpqam5kSsREREREVGe0+jmth/j6uoKV1dX9OzZE0uWLMHp06dx+vRp2NraYtCgQRg6dChkMpmuciUiIiIiIspz2S6aXr58iYMHD+LgwYN4/vw5PvnkE0yePBktWrTA6dOnsXr1ajx8+BD/+9//dJkvERERERFRntK6aNq9ezcOHjyI69evw9TUFO3atcPChQtRt25d5TL29vZ49+4ddu7cyaKJiIiIiIjyNa2LptmzZ8PZ2RleXl7w8PBA0aJFM13OwcEBvXr1ynGCRERERERE+qR10fTLL7+gWrVqH53/+vVrlClTBl26dMlJXkRERERERAZB69HzOnXq9NH7M127dg3t27fPcVJERERERESGQqOWpo0bNyI+Ph4AIEkSdu/ejTNnzmRY7saNGzAxMdFthkRERERERHqkUdGUlJQEPz8/AIAgCNi9e3eGZURRhKWlJUaPHq3bDImIiIiIiPRIo6Jp9OjRymLI0dERgYGBcHZ2ztXEiIiIiIiIDIHWA0Hcv38/N/IgIiIiIiIySBoVTTNnzsSYMWNQsWJFzJw5U+2ygiBg0aJFOkmOiIiIiIhI3zQqmi5fvoxBgwYp/6+OIAg5z4qIiIiIiMhAaFQ0/f7775n+n4iIiIiIqKDT+j5NABAUFITVq1crH9+9excTJkzAnTt3dJYYERERERGRIdC6aPrjjz8waNAgnDt3TjlNEAQ8ffoUffv2xbVr13SaIBERFUwymQiZLFvn7oiIiPKU1r9Wq1atQocOHbBjxw7ltOrVq+PgwYNo3749li9frtMEiYioYDG2toZCUsDKyhxWVub6ToeIiChLWhdNjx49QpcuXTId8KFLly4ckpyIiNQyKloEoiDC99JG/HT7oL7TISIiypLWRZOlpSWePHmS6bwXL17AwsIix0kREVHB9zL6NcLiwvWdBhEZMFEUYGQkwshIhChyhGbSH62Lps8//xw+Pj44deqUyvSzZ8/Cx8cHn3/+uc6SIyIi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DRZNREREREREamR7IAgiIqKsiKIAURQgk/EcHRER5V8smoiIKFeIogBrawsWTERElO/xl4yIiHJFeguT9/YgbDlyV6N1ZDKRRRYRERkctjQREVGuCgmNASRJ7TIyY3MoJAlWVuZ5lBUREZHmeDqPiIj0TiYzhSgIWH/zCfb//VLf6RAREalgSxMRERmMV7GJWTVKERER5Tm2NBEREREREanBoomIiIiIiEgNFk1ERERERERqsGgiIiIiIiJSg0UTERERERGRGiyaiIiIiIiI1GDRREREREREpAaLJiIiIiIiIjVYNBEREREREanBoomIiIiIiEgNFk1ERERERERqsGgiIiIiIiJSg0UTERERERGRGiyaiIiIiIiI1GDRREREREREpIaRvhMgKixEUYAoCpDJeK6CiIiIKD9h0USUB0RRgLWNOWSiTN+pEBEREZGWeMqbKA+IogCZKIPvpY346fZBfadDRERERFpgSxNRHnoZ/RqSJOk7DSIiIiLSAluaiIiIiIiI1GDRREREREREpAaLJiIiIiIiIjVYNBEREREREanBoomIiIiIiEgNFk1ERERERERqsGgiIiIiIiJSg0UTERERERGRGiyaiIiIiIiI1GDRREREREREpAaLJiIiIiIiIjVYNBEREREREanBoomIiIiIiEgNFk1ERERERERqsGgiIiIiIiJSg0UTERERERGRGiyaiIiIiIiI1DDSdwJERJQzoihAFAXIZDwPRkRElBtYNBF9IP0AFAAUCgkKhaTnjIg+ThQFWFtbsGAiIiLKRQb1KxsQEIABAwaoTLt37x769++POnXqoFWrVtiyZYuesqPCQBQF2Fibw8amSNqftbmygCIyROktTN7bg7DlyF19p0NERFQgGUzRtH37dqxcuVJl2rt37zBkyBB88skn2Lt3L8aOHQtvb2/s3btXP0lSgSeKAkSZDA+Wr8SD5SshymQsmihfCAmNQVhEvL7TICIiKpD03j0vNDQUc+bMweXLl1G5cmWVebt27YKxsTHmzZsHIyMj2NnZ4dmzZ1i7di26d++un4SpUIh/EaLvFIiIiIjIQOi9pemvv/6CsbExfv75Zzg7O6vMu3btGtzd3WFk9F9t16BBAzx9+hTh4eF5nSoRERERERVCem9patWqFVq1apXpvNevX8Pe3l5lWqlSpQAAr169gq2tbba3a2Sk93pRY+kXeOvqQm9dxitouWW2rKbTtI2bk3gfW7+gvA55Fa8g5JZbA0Coi2vIub0/n+8R/cVjbvqPZejxNImlze9vQXodcnrcog1Dft4Mjd6LJnUSExNhYmKiMs3U1BQAkJSUlO24oijAxqZIjnLTBysrc4ONV5Bzy2x9Q91fQ81L17F0Ha8w5abL7Rpybtosl9exdB2Puek/lq7jGXJuuo6nbaysli9Mr4MuYxry82YoDLpoMjMzQ3Jyssq09GLJwsIi23EVCgnR0fnngmmZTISVlTmioxMglysMKl5Byy19nfdFRycAUP0S0Da/zOJ+uI2c7G9Bex2Ym+axsnpvZZe67RpybtrkpwldxRIEAVZWZhDFtDOwCoUC0dGJkKTs39KgILx/mVv+yU3X8TSJ9bHf5MyWL0ivgzbfnYZ0/KDr5y2vWFmZa9Q6ZtBFU5kyZRAWFqYyLf1x6dKlcxQ7NTX/vJjp5HKFTvPWZbyCnFtmH3xD3V9DzUvXsXQdrzDlpsvtGnJu2iyny21+jJGRCFEU8eT2DgBAFae+kCSJn3s9xmNuhhFP21hZLV+YXgddxjTk581QGHSnw3r16iEoKAhyuVw57dKlS6hSpQpKlCihx8yIiIi0lxAXhoS4sKwXJCIig2LQRVP37t0RGxuL7777Dg8fPsS+ffuwefNmjBw5Ut+pERERERFRIWHQRVOJEiWwfv16PHnyBF27doWfnx+mTZuGrl276js1IiIiIiIqJAzqmqbFixdnmObk5ITAwEA9ZENERERERGTgLU1ERERERET6xqKJiIiIiIhIDRZNREREREREarBoIiIiIiIiUoNFExERERERkRosmoiIiIiIiNRg0URERERERKQGiyYiIiIiIiI1WDQRERERERGpwaKJiIiIiIhIDRZNREREREREarBoIiIiIiIiUoNFExERERERkRosmoiIiIiIiNRg0URERERERKQGiyYiIiIiIiI1WDQRERERERGpwaKJiIiIiIhIDRZNREREREREarBoIiIiIiIiUoNFExERERERkRosmoiIiIiIiNQw0ncCRATIZGnnLxQKCQqFpOdsiIiIiOh9LJqI9MjIxBIKSYKVlTkAQK6QEPkujoUTERERkQFh0USkR0bGZhAFAetvPgEADK9TBaIosGgiIiIiMiAsmogMwKvYRH2nQEREREQfwYEgiIiI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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# New capacity installed by technology and year\n", + "years = ['y2020', 'y2025', 'y2030', 'y2035', 'y2040', 'y2045', 'y2050']\n", + "filtered_data = {}\n", + "\n", + "# Function to filter and process the data\n", + "def process_data(year):\n", + " data = data_results['vCENewCap'][data_results['vCENewCap'].sYear == year]\n", + " data = data[~data.sCE.str.startswith(('sPE2TE', 'sTE2TE'))]\n", + " data = data.drop(columns=['sYear']).set_index('sCE')\n", + " return data\n", + "\n", + "# Process data for each year\n", + "for year in years:\n", + " filtered_data[year] = process_data(year)\n", + "\n", + "# Create a figure and a set of subplots\n", + "fig, ax = plt.subplots(1, 1, figsize=(10, 5))\n", + "\n", + "# Set the bar width\n", + "barWidth = 0.15\n", + "\n", + "# Set the position of the bars on the x-axis\n", + "positions = [np.arange(len(filtered_data['y2020'])) + i * barWidth for i in range(len(years))]\n", + "\n", + "# Define colors for each year\n", + "colors = ['b', 'r', 'g', 'y', 'c', 'm', 'k']\n", + "\n", + "# Make the plot\n", + "for i, year in enumerate(years):\n", + " plt.bar(positions[i], filtered_data[year].vCENewCap, color=colors[i], width=barWidth, label=year[1:])\n", + "\n", + "# Add xticks on the middle of the group bars\n", + "plt.xlabel('Technologies', fontweight='bold')\n", + "plt.xticks([r + barWidth * (len(years) - 1) / 2 for r in range(len(filtered_data['y2020']))], filtered_data['y2020'].index, rotation=90)\n", + "plt.ylabel('Capacity [GW]')\n", + "plt.title('New Capacity by Year and Technology')\n", + "# Create legend & Show graphic\n", + "plt.legend()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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/Raurq4GWc6sWbNw+PBhdO7cWa+u1YkMpXv37vjyyy+xa9cu5OXloUGDBli2bFmpTjS47xI93XiPFBERERERkZ54jxQREREREZGeWEgRERERERHpifdI4f4Tx1NSUmBra1vmg/KIiIiIiOj5IITA3bt34e7uDqWy/PNOLKQApKSkwMPDw9hpEBERERGRifj7779Rq1atcsezkAJga2sL4P7GsrOzM3I22tRqNfbu3Qt/f39YWFiYVDzmZhrxmJvxYzG3ZzMeczN+LOZmGvFMOTe54zE348cyBVlZWfDw8JBqhPKwkAKky/ns7OxMspCqUqUK7OzsZPvQyBWPuZlGPOZm/FjM7dmMx9yMH4u5mUY8U85N7njMzfixTMnjbvlhZxNERERERER6YiFFRERERESkJxZSREREREREeuI9UkRERERETwGFQoH8/HwUFRVVOpZarYa5uTny8vIqHU/OWE+CmZkZzM3NK/3YIxZSREREREQmLicnBy4uLrh27Zoszz0VQsDV1RV///13pePJGetJqVKlCtzc3GBpaVnhGCykiIiIiIhMWFFREf799184OjrC3d0dZmZmlY6p0WiQnZ0NGxubRz509knHMjQhBAoKCnDz5k0kJyejYcOGFc6ZhRQRERERkQlTq9UQQsDOzg4qlUqWYkWj0aCgoADW1tayFFJyxXoSVCoVLCwscPXqVSnvijD9NSUiIiIioqfmsrmngRwFHwspIiIiIiIiPbGQIiIiIiIi0hPvkSIiIiIiegpV7ko/JQAHveYQojLLe/bwjBQREREREclu7ty5aNeuHWxtbeHs7IzAwEAkJSVpTZOXl4fg4GA4OTnBxsYGQUFBSEtLk8afOnUKgwYNgoeHB1QqFby8vLBkyZJSy4qPj8cLL7wAKysrNGjQAGvWrDH06rGQIiIiIiIi+SUkJCA4OBhHjx5FbGws1Go1/P39kZOTI00TGhqKnTt3YuPGjUhISEBKSgr69+8vjU9MTISzszO+//57nD17Fh9//DGmTp2K5cuXS9MkJyejd+/e8PX1xcmTJzFx4kS888472LNnj0HXj5f2ERERERGR7GJiYrSG16xZA2dnZyQmJqJr167IzMzE6tWrER0dje7duwMAoqKi4OXlhaNHj6Jjx44YOXKkVox69erhyJEj2LJlC0JCQgAAkZGR8PT0xJdffgkA8PLy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zh2nr1u3DmPGjNFqi46Oxv79+7F//34sWLAAGzZskD1BIiIiIiIiU6NzIXXp0iW0aNFCGra2ttZ6gFX79u1x7tw5ebMjIiIiIiIyQTpf2peRkaF1T9TNmze1xms0Gq3xREREREREzyqdz0jVqlULZ86cKXf86dOnUatWLVmSIiIiIiIiMmU6F1KvvPIKpk+fjry8vFLjcnNzER4ejt69e8uaHBERERERkSnS+dK+jz76CBs2bEDjxo0REhKCRo0aAQCSkpKwfPlyFBYW4qOPPjJYokRERERERKZC50LKxcUFhw8fxrhx4zBlyhQIcb/nfoVCgZ49e2LFihVwcXExWKJERERERESmQudCCgA8PT0RExOD9PR0XLp0CQDQoEEDODo6GiQ5IiIiIiIiU6RXIVXM0dER7du3lzsXIiIiIiKip4JOnU30798fWVlZOgcdMmQIbty4UeGkiIiIiIiITJlOZ6S2b99e6rlR5RFCYOfOnZg9ezacnZ0rlRwREREREZEp0qmQEkJIvfQRERERERE973QqpPbv36934Jo1a+o9DxERERER0dNAp0KqW7duhs6DiIiIiIjoqaFTZxNERERERET0AAspIiIiIiIiPbGQIiIiIiIi0hMLKSIiIiIiIj3pXUjNmDEDV69eNUQuRERERERETwW9C6nt27ejfv366NGjB6Kjo5Gfn2+IvIiIiIiIiEyW3oXUyZMncfz4cTRr1gwTJkyAq6srxo0bh+PHj8ueXFFREaZNmwZPT0+oVCrUr18fs2fPhhBCmkYIgenTp8PNzQ0qlQp+fn64ePGi7LkQET1L4uMV0ouIiIj0V6F7pNq0aYOlS5ciJSUFq1evxj///IPOnTujZcuWWLJkCTIzM2VJbt68eVi5ciWWL1+O8+fPY968eZg/fz6WLVsmTTN//nwsXboUkZGROHbsGKpWrYqAgADk5eXJkgMREREREdHDKtXZhBACarUaBQUFEEKgWrVqWL58OTw8PLB+/fpKJ3f48GH07dsXvXv3Rt26dfH666/D398fv/32m7T8xYsX45NPPkHfvn3RsmVLfPfdd0hJScG2bdsqvXwiIiIiIqKymFdkpsTERERFReGHH36AlZUVhg4dioiICDRo0AAAsGzZMrz//vt48803K5Vcp06d8N///hd//fUXGjVqhFOnTuHgwYNYuHAhACA5ORmpqanw8/OT5rG3t0eHDh1w5MgRDBw4sMy4+fn5Wvd2ZWVlAQDUajXUanWlcpZbcT5y5SVnPOZmGvGYm/FjyR3vSeQmhEr6twolLpd+0AwVHgw8HMMUc5M7v+d9HzGFWHLHY27GjyVHPFWJY4EaKqj/v0GlLPu48CRzM2S85yk3Y9N1PRSi5A1HOmjRogUuXLgAf39/jB49Gq+++irMzMy0prl16xacnZ2h0Wj0CV2KRqPBRx99hPnz58PMzAxFRUX47LPPMHXqVAD3z1h17twZKSkpcHNzk+Z74403oFAoyj0rNnPmTISHh5dqj46ORpUqVSqVMxERERERPb3u3buHwYMHIzMzE3Z2duVOp/cZqTfeeAMjR45EzZo1y52mevXqlS6iAGDDhg1Yt24doqOj0axZM5w8eRITJ06Eu7s7hg0bVuG4U6dORVhYmDSclZUFDw8P+Pv7P3JjGYNarUZsbCx69uwJCwsLk4rH3EwjHnMzfqynMbeDB+2l8b2xW/r37t4o0f5goPjeV1POTe78nvd9xBRiMTfTiGdqudk/OEQgE/ZQq1SI/eYbjDwzErma3PvtUyp2v76prevzmpuxFV+t9jh6F1LF90I9LDc3FwsWLMD06dP1DVmuSZMmYcqUKdIlei1atMDVq1cxd+5cDBs2DK6urgCAtLQ0rTNSaWlpaN26dblxraysYGVlVardwsLCZN98uXOTMx5zM414zM34seSOZ8jcFIpcqT0XD3ruK9GMXORqzfu05CZ3fs/rPmJKseSOx9yMH6sy8XJLHAssShwLcjW5UiFV2TxNZV0NHUvueKb8XVofuq6D3p1NhIeHIzs7u1T7vXv3yrxcrjLu3bsHpVI7RTMzM+lsl6enJ1xdXbFv3z5pfFZWFo4dOwZvb29ZcyEiIiIiIipWoTNSCkXp546cOnUKjo6OsiRV7NVXX8Vnn32G2rVro1mzZvjjjz+wcOFCjBw5EgCgUCgwceJEfPrpp2jYsCE8PT0xbdo0uLu7IzAwUNZciIiIiIiIiulcSFWrVg0KhQIKhQKNGjXSKqaKioqQnZ2NsWPHyprcsmXLMG3aNLz33nu4ceMG3N3d8e6772pdPjh58mTk5ORgzJgxyMjIwEsvvYSYmBhYW1vLmgsREREREVExnQupxYsXQwiBkSNHIjw8HPYl7vSztLRE3bp1Zb+cztbWFosXL8bixYvLnUahUGDWrFmYNWuWrMsmIiIiIiIqj86FVHEveZ6enujUqdMzcSMZERERERFRRehUSGVlZUndgrdp0wa5ubnILdllSgmm1n04ERERERGR3HQqpKpVq4Z///0Xzs7OcHBwKLOzieJOKIqKimRPkoiIiIiIyJToVEjFxcVJPfLFxcWVWUgRERERERE9L3QqpLp16yb928fHx1C5EBERERERPRX0fiBvVFQUNm7cWKp948aN+Pbbb2VJioiIiIiIyJTpXUjNnTsX1atXL9Xu7OyMOXPmyJIUERERERGRKdO7kLp27Ro8PT1LtdepUwfXrl2TJSkiIiIiIiJTpnch5ezsjNOnT5dqP3XqFJycnGRJioiIiIiIyJTpXUgNGjQI77//Pvbv34+ioiIUFRUhLi4OEyZMwMCBAw2RIxERERERkUnRqde+kmbPno0rV66gR48eMDe/P7tGo8HQoUN5jxQRERERET0X9C6kLC0tsX79esyePRunTp2CSqVCixYtUKdOHUPkR0REREREZHL0LqSKNWrUCI0aNZIzFyIiIiIioqdChQqpf/75Bzt27MC1a9dQUFCgNW7hwoWyJEZERERERGSq9C6k9u3bh9deew316tXDhQsX0Lx5c1y5cgVCCLzwwguGyJGIiIiIiMik6N1r39SpU/Hhhx/izz//hLW1NTZv3oy///4b3bp1w4ABAwyRIxERERERkUnRu5A6f/48hg4dCgAwNzdHbm4ubGxsMGvWLMybN0/2BImIiIiIiEyN3oVU1apVpfui3NzccPnyZWncrVu35MuMiIiIiIjIROl9j1THjh1x8OBBeHl54ZVXXsEHH3yAP//8E1u2bEHHjh0NkSMREREREZFJ0buQWrhwIbKzswEA4eHhyM7Oxvr169GwYUP22EdERERERM8FvQupevXqSf+uWrUqIiMjZU2IiIiIiIjI1FX4gbwnTpzA+fPnAQBNmzZF27ZtZUuKiIiIiIjIlOldSP3zzz8YNGgQDh06BAcHBwBARkYGOnXqhB9//BG1atWSO0ciIiIiIiKTonevfe+88w7UajXOnz+P9PR0pKen4/z589BoNHjnnXcMkSMREREREZFJ0fuMVEJCAg4fPozGjRtLbY0bN8ayZcvQpUsXWZMjIiIiIiIyRXqfkfLw8IBarS7VXlRUBHd3d1mSIiIiIiIiMmV6F1ILFizA+PHjceLECantxIkTmDBhAr744gtZkyMiIiIiIjJFel/aN3z4cNy7dw8dOnSAufn92QsLC2Fubo6RI0di5MiR0rTp6enyZUpERERERGQi9C6kFi9ebIA0iIiIiIiInh56F1LDhg0zRB5ERERERERPjQo/kBcA8vLyUFBQoNVmZ2dXqYSIiIiIiIhMnd6dTeTk5CAkJATOzs6oWrUqqlWrpvUiIiIiIiJ61uldSE2ePBlxcXFYuXIlrKyssGrVKoSHh8Pd3R3fffedIXIkIiIiIiIyKXpf2rdz505899138PHxwYgRI9ClSxc0aNAAderUwbp16zBkyBBD5ElERERERGQy9D4jlZ6ejnr16gG4fz9UcRfnL730Eg4cOCBvdkRERERERCZI70KqXr16SE5OBgA0adIEGzZsAHD/TJWDg4OsyREREREREZkivQupESNG4NSpUwCAKVOmICIiAtbW1ggNDcWkSZNkT5CIiIiIiMjU6H2PVGhoqPRvPz8/XLhwAYmJiWjQoAFatmwpa3JERERERESmSO8zUg+rU6cO+vfvb7Ai6vr163jrrbfg5OQElUqFFi1a4MSJE9J4IQSmT58ONzc3qFQq+Pn54eLFiwbJhYiIiIiICNCjkIqLi0PTpk2RlZVValxmZiaaNWuGX3/9Vdbk7ty5g86dO8PCwgI///wzzp07hy+//FLreVXz58/H0qVLERkZiWPHjqFq1aoICAhAXl6erLkQEREREREV0/nSvsWLF2P06NGws7MrNc7e3h7vvvsuFi5ciC5dusiW3Lx58+Dh4YGoqCipzdPTU/q3EAKLFy/GJ598gr59+wIAvvvuO7i4uGDbtm0YOHCgbLkQEREREREV07mQOnXqFObNm1fueH9/f3zxxReyJFVsx44dCAgIwIABA5CQkICaNWvivffew+jRowEAycnJSE1NhZ+fnzSPvb09OnTogCNHjpRbSOXn5yM/P18aLj7LplaroVarZV2HyirOR6685IzH3EwjHnMzfiy54z2J3IRQSf9WQTxof9AMFR4MPBzDFHOTO7/nfR8xhVhyx2Nuxo8lRzxViWOBGiqo/79BpSz7uPAkczNkvOcpN2PTdT0UQgjx+MkAa2trnDlzBg0aNChz/KVLl9CiRQvk5ubqnqUOywSAsLAwDBgwAMePH8eECRMQGRmJYcOG4fDhw+jcuTNSUlLg5uYmzffGG29AoVBg/fr1ZcadOXMmwsPDS7VHR0ejSpUqsuVPRERERERPl3v37mHw4MHIzMws82q8YjqfkapZs+YjC6nTp09rFTNy0Gg0ePHFFzFnzhwAQJs2bXDmzBmpkKqoqVOnIiwsTBrOysqCh4cH/P39H7mxjEGtViM2NhY9e/aEhYWFScVjbqYRj7kZP9bTmNvBg/bS+N7YLf17d2+UaH8wkJmZafK5yZ3f876PmEIs5mYa8UwtN/sHhwhkwh5qlQqx33yDkWdGIldz/wf9zCmZ5cxt2NwMGe95ys3YyuoToiw6F1KvvPIKpk2bhpdfflk6U1QsNzcXM2bMQJ8+ffTL8jHc3NzQtGlTrTYvLy9s3rwZAODq6goASEtL0yri0tLS0Lp163LjWllZwcrKqlS7hYWFyb75cucmZzzmZhrxmJvxY8kdT+7cqn9ZXfqSsb/bg/ZcKKR/K3JLtj8YeDgPQ243RYkkKpKb3Pk9T/sIczN+POb2eCUvfrIocSzI1eRKx7jK5mkq62roWHLHM+Xv0vrQdR107rXvk08+QXp6Oho1aoT58+dj+/bt2L59O+bNm4fGjRsjPT0dH3/8cYUTLkvnzp2RlJSk1fbXX3+hTp06AO53POHq6op9+/ZJ47OysnDs2DF4e3vLmgsREREREVExnc9Iubi44PDhwxg3bhymTp2K4lurFAoFAgICEBERARcXF1mTCw0NRadOnTBnzhy88cYb+O233/Df//4X//3vf6VlT5w4EZ9++ikaNmwIT09PTJs2De7u7ggMDJQ1FyIiIiIiomI6F1LA/Yfv/vTTT7hz5w4uXboEIQQaNmyo9VwnObVr1w5bt27F1KlTMWvWLHh6emLx4sUYMmSINM3kyZORk5ODMWPGICMjAy+99BJiYmJKXX5IREREREQkF70KqWLVqlVDu3bt5M6lTH369HnkvVcKhQKzZs3CrFmznkg+REREREREOt8jRURERERERPexkCIiIiIiItITCykiIiIiIiI9sZAiIiIiIiLSEwspIiIiIiIiPbGQIiIiIiIi0hMLKSIiIiIiIj2xkCIiIiIiItITCykiIiIiIiI9sZAiIiIiIiLSEwspIiIiIiIiPbGQIiIiIiIi0hMLKSIiIiIiIj2xkCIiIiIiItITCykiIiIiIiI9sZAiIiIiIiLSEwspIiIiIiIiPbGQIiIiIiIi0hMLKSIiIiIiIj2xkCIiIiIiItITCykiIiIiIiI9mRs7ASIiIvvP7ZGryQUA7O9m5GSIiIh0wDNSREREREREemIhRUREREREpCcWUkRERERERHpiIUVERERERKQnFlJERERERER6YiFFRERERESkJxZSRETPMoUCsLc3dhZERETPHBZSREREREREemIhRUREREREpCcWUkRERERkUArFgxfRs4KFFBERERERkZ5YSBEREREREemJhRQREREREZGeWEgRERERERHpiYUUERERERGRnlhIERERERER6empKqQ+//xzKBQKTJw4UWrLy8tDcHAwnJycYGNjg6CgIKSlpRkvSSIiIiIieuaZGzsBXR0/fhxfffUVWrZsqdUeGhqK3bt3Y+PGjbC3t0dISAj69++PQ4cOGSlTIiIiIqLKK/ncrQKVPfDDD4C9PRT/yZXa93d7MI0v9t9v833Q5iN8DJzl8+upOCOVnZ2NIUOG4Ouvv0a1atWk9szMTKxevRoLFy5E9+7d0bZtW0RFReHw4cM4evSoETMmIiIiIqJn2VNxRio4OBi9e/eGn58fPv30U6k9MTERarUafn5+UluTJk1Qu3ZtHDlyBB07diwzXn5+PvLz86XhrKwsAIBarYZarTbQWlRMcT5y5SVnPOZmGvGYm/FjyR1P1txUKqhVqvv/VKqkZiFKTIIHA0JVsv3BwMM5yb3d5MhN7vyem31E5njMzfix5I4nRyxVic9vZeNpxULZx7iKxja190FrXf9/QK1SQVXiVEhZx0xRxvaWOzdDxTIFuq6HQoiSm9/0/Pjjj/jss89w/PhxWFtbw8fHB61bt8bixYsRHR2NESNGaBVFANC+fXv4+vpi3rx5ZcacOXMmwsPDS7VHR0ejSpUqBlkPIiIiIiIyfffu3cPgwYORmZkJOzu7cqcz6TNSf//9NyZMmIDY2FhYW1vLFnfq1KkICwuThrOysuDh4QF/f/9HbixjUKvViI2NRc+ePWFhYWFS8ZibacRjbsaPZdK52dtDrVIh9ptvMPLMSORq7l9Xv/ulB5P0xm7p37t7l2x/MJCZmSl/biXiyZGb3Pk9N/sIczOJeM96bvb2D/5961bl4pWMlYmyj3GZUzLLmfvRTO190NpuKlfEfvMNeo4cieoTH9wjVdYxs+Tx8qXMEhPImJuhYpmC4qvVHsekC6nExETcuHEDL7zwgtRWVFSEAwcOYPny5dizZw8KCgqQkZEBBwcHaZq0tDS4urqWG9fKygpWVlal2i0sLEz2zZc7NznjMTfTiMfcjB9L7niyxMp98Mc2V5MrfckoeQNzLh4MKHJLtj8YeDgP2dbT/v7N03LmJmt+MseSOx5zM34sueM9q7mVOBShOERF42nFQtnHuMqus6m8D2Wtq0Xug/UEyj5mKrS296OXayr7iCnRdR1MupDq0aMH/vzzT622ESNGoEmTJvjPf/4DDw8PWFhYYN++fQgKCgIAJCUl4dq1a/D29jZGykRERERE9Bww6ULK1tYWzZs312qrWrUqnJycpPZRo0YhLCwMjo6OsLOzw/jx4+Ht7V1uRxNERERERESVZdKFlC4WLVoEpVKJoKAg5OfnIyAgACtWrDB2WkRERERE9Ax76gqp+Ph4rWFra2tEREQgIiLCOAkREREREdFz56l4IC8REREREZEpeerOSBERERERkW4UJbr1M/HHxz51eEaKiIiIiIhITyykiIiIiIiI9MRCikgXJR8tTkRERETPPRZSREREREREemIhRUREREREpCf22kckA0WJ55sJHx+j5UFERERETwbPSBEREREREemJhRQREREREZGeWEgRERERERHpiYUUERERERGRntjZBBHRM0ahePBvYbw0iIiInmk8I0VERERERKQnFlJERERERER6YiFFRERERESkJxZSREREREREemIhRUREREREpCcWUkRERERERHpi9+dEerD/3B65mlwAgJjBjqWJiIiInlcspIhMXLwiXvq3j/AxWh5ERERE9AAv7SMiIiIiItITz0gRVVB8vKLE0H5ZYyvi48uMrFA8WKYQvLSQiIiIyFhYSBGZCEMWZkREREQkL17aR0REREREpCcWUkRERERERHpiIUVUDoXiwYuIiIiIqCQWUkRE9ETxRwoiInoWsJAiIiIiIiLSE3vtIyIiMmF87AERkWniGSkiIiIiIiI9sZAiIiIiIiLSEwspIiIiIiIiPbGQIiIiIiIi0hMLKSIiIiIiIj2xkCIiIiIiItITCykiIiIiIiI9sZAiIiIiIiLSk0kXUnPnzkW7du1ga2sLZ2dnBAYGIikpSWuavLw8BAcHw8nJCTY2NggKCkJaWpqRMiYiIiIioueBSRdSCQkJCA4OxtGjRxEbGwu1Wg1/f3/k5ORI04SGhmLnzp3YuHEjEhISkJKSgv79+xsxayIiIiIietaZGzuBR4mJidEaXrNmDZydnZGYmIiuXbsiMzMTq1evRnR0NLp37w4AiIqKgpeXF44ePYqOHTsaI20iIiIiInrGmXQh9bDMzEwAgKOjIwAgMTERarUafn5+0jRNmjRB7dq1ceTIkXILqfz8fOTn50vDWVlZAAC1Wg21Wm2o9CukOB+58pIz3rOem0pVIt7/D6iUDxqFKDEtHgzossyy8hPiQeyS8Uo0Q4UHAw/HeFbfB0PFe5Zz09p3odJr/30S+1tFP1uPy02u/AwRqzLxVCp+7uWKx9yMF0vrc/8EjnEVjW1q70NZx0u1SgVViWvKyjpmPu3HS2PTdT0UQpTc/KZLo9HgtddeQ0ZGBg4ePAgAiI6OxogRI7SKIgBo3749fH19MW/evDJjzZw5E+Hh4aXao6OjUaVKFfmTJyIiIiKip8K9e/cwePBgZGZmws7OrtzpnpozUsHBwThz5oxURFXG1KlTERYWJg1nZWXBw8MD/v7+j9xYxqBWqxEbG4uePXvCwsLCpOI967nZ2z/49y2VK2K/+QYjz4xEriYXALD7pQfje2O39O/Ml0qM0CO/gwcfLLBkvN29Sy7nwUDxGdpn/X0wtdzsS+wYxe+BqeT2IMcH/86EPdQqlc7775PY3yr62XpcbnLlZ4hY+sY7aP/gbx0/98zN2PFk/9zfMvwxLnNKZjlzP5qpvQ9lHS97jhyJ6hNzpfayjplP+/HS2IqvVnucp6KQCgkJwa5du3DgwAHUqlVLand1dUVBQQEyMjLg4OAgtaelpcHV1bXceFZWVrCysirVbmFhYbJvvty5yRnvWc0t98ExCha4P5CryZUO0gpFiWnxYECf5ZXMT6F4sMCS8Uo0Ixe5WvOWF0sOpvI+GDqevrFyc8t/D4ydW7Gy9l1At/33SexvFf1s6ZpbZfMzZCxd4ylyH6w3P/fyx2NuTz6W1ufeonLxdDnGHTpkKbX7+Oh/8ZWpvA9lratF7oP1BMo+Zj4rx0tj0XUdTLrXPiEEQkJCsHXrVsTFxcHT01NrfNu2bWFhYYF9+/ZJbUlJSbh27Rq8vb2fdLpERERERPScMOkzUsHBwYiOjsb27dtha2uL1NRUAPcvrVGpVLC3t8eoUaMQFhYGR0dH2NnZYfz48fD29maPfUQkq3hFvLFTICIiIhNi0oXUypUrAQA+Pj5a7VFRURg+fDgAYNGiRVAqlQgKCkJ+fj4CAgKwYsWKJ5wpERERERE9T0y6kNKlQ0Fra2tEREQgIiLiCWRERERERERk4vdIERERERERmSKTPiNFRGRMivh46d/7jZcGERERmSCekSIiIiIiItITCykiIiIiIiI9sZAiIiIiIiLSE++RIiIqIT6+xCPieWcUPUG8J4+I6OnCQoqIiIiIiHSiUDz4wVGXRxU9y3hpHxERERERkZ5YSBEREREREemJhRQRERERaVEoHryIqGy8R4qInnuK8AffFPZ3M2IiRERE9NTgGSkiIiIiIiI9sZAiMiCFQiG9yMTY22v/n4iIiEgPvLSPiIiIiIjKFa+IN3YKJomFFJHMeLAxXSVPDBaojJcHERERPf14aR8REREREZGeWEgRERERERHpiZf2ERHRE6Hd6YowWh5ERERyYCFFRERkJPHxJYvL/UbLg4iI9MdCiojoCSvZIYkvfKV/C8GzNERERE8LFlJET0jxVU38rkxERESmThEfL/2b58vLxkKKyIjsP7dHriYXALC/m5GTIYN6Xv8g8XEARET0rGKvfURERERERHriGSkiIgNhRwJERETPLhZSREQy4uWaREREzwde2kdERERERKQnnpEiIiJZPa8daxAR0fOFhRQREREREfHeXj3x0j4iIiIiIiI9sZAiIqoshQKwtzd2FgAAhUIBQPHY6YiISH4KxYMXPft4aR8REVUaLwfRHXt2JCJ6NrCQIiKqoOJfHIVx00C8It7IGRARET1/WEiZoJKngwtU9sAPPwD29lD8J1dqFzOM/dWN6Omh0LrG4tn47LBnPCIi3ZQ8XgofH6PlQc8eFlJE9MzQKi58jZeHofDyuaeYQgGoVPd/GCMioyl5Bt8XD/5QCGGAH9n4uX/msZAioqdO+feYPHvFhSL8QfFkavfTmHJuRGTC7B9cbYN794ydzXOP921WHAspIno68Jc9IqJnTvEPMiW/wPv4PBuXYNOzj4UUEclK6x6/AvliPVd/Vkv+WvsfYydDFfXc7r9ElWSMe5qKP6/l3ZteXOhVtMgredaH97k/O/gcKaInTe5nDhXHMpHnGFHF8dkjRETa4hXx0ovI1DwzhVRERATq1q0La2trdOjQAb/99puxUyIievawcCci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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Active capacity by technology and year\n", + "y2020_TotActCap_CE = data_results['vCEActCap'][data_results['vCEActCap'].sYear=='y2020']\n", + "y2025_TotActCap_CE = data_results['vCEActCap'][data_results['vCEActCap'].sYear=='y2025']\n", + "y2030_TotActCap_CE = data_results['vCEActCap'][data_results['vCEActCap'].sYear=='y2030']\n", + "y2035_TotActCap_CE = data_results['vCEActCap'][data_results['vCEActCap'].sYear=='y2035']\n", + "y2040_TotActCap_CE = data_results['vCEActCap'][data_results['vCEActCap'].sYear=='y2040']\n", + "y2045_TotActCap_CE = data_results['vCEActCap'][data_results['vCEActCap'].sYear=='y2045']\n", + "y2050_TotActCap_CE = data_results['vCEActCap'][data_results['vCEActCap'].sYear=='y2050']\n", + "\n", + "# Avoid all the variables in sCE that begin with sPE2TE and sTE2TE\n", + "y2020_TotActCap_CE = y2020_TotActCap_CE[~y2020_TotActCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2025_TotActCap_CE = y2025_TotActCap_CE[~y2025_TotActCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2030_TotActCap_CE = y2030_TotActCap_CE[~y2030_TotActCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2035_TotActCap_CE = y2035_TotActCap_CE[~y2035_TotActCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2040_TotActCap_CE = y2040_TotActCap_CE[~y2040_TotActCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2045_TotActCap_CE = y2045_TotActCap_CE[~y2045_TotActCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2050_TotActCap_CE = y2050_TotActCap_CE[~y2050_TotActCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2020_TotActCap_CE = y2020_TotActCap_CE[~y2020_TotActCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2025_TotActCap_CE = y2025_TotActCap_CE[~y2025_TotActCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2030_TotActCap_CE = y2030_TotActCap_CE[~y2030_TotActCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2035_TotActCap_CE = y2035_TotActCap_CE[~y2035_TotActCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2040_TotActCap_CE = y2040_TotActCap_CE[~y2040_TotActCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2045_TotActCap_CE = y2045_TotActCap_CE[~y2045_TotActCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2050_TotActCap_CE = y2050_TotActCap_CE[~y2050_TotActCap_CE.sCE.str.startswith('sTE2TE')]\n", + "\n", + "# Delete the column sYear and make the index the column sCE\n", + "y2020_TotActCap_CE = y2020_TotActCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2025_TotActCap_CE = y2025_TotActCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2030_TotActCap_CE = y2030_TotActCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2035_TotActCap_CE = y2035_TotActCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2040_TotActCap_CE = y2040_TotActCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2045_TotActCap_CE = y2045_TotActCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2050_TotActCap_CE = y2050_TotActCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "\n", + "# Create a figure and a set of subplots\n", + "fig, ax = plt.subplots(1, 1, figsize=(10, 5))\n", + "\n", + "# Set the bar width\n", + "barWidth = 0.15\n", + "\n", + "# Set the position of the bars on the x-axis\n", + "r1 = np.arange(len(y2020_TotActCap_CE))\n", + "r2 = [x + barWidth for x in r1]\n", + "r3 = [x + barWidth for x in r2]\n", + "r4 = [x + barWidth for x in r3]\n", + "r5 = [x + barWidth for x in r4]\n", + "r6 = [x + barWidth for x in r5]\n", + "r7 = [x + barWidth for x in r6]\n", + "r8 = [x + barWidth for x in r7]\n", + "r9 = [x + barWidth for x in r8]\n", + "\n", + "# Make the plot\n", + "plt.bar(r1, y2020_TotActCap_CE.vCEActCap, color='b', width=barWidth, label='2020')\n", + "plt.bar(r2, y2025_TotActCap_CE.vCEActCap, color='r', width=barWidth, label='2025')\n", + "plt.bar(r3, y2030_TotActCap_CE.vCEActCap, color='g', width=barWidth, label='2030')\n", + "plt.bar(r4, y2035_TotActCap_CE.vCEActCap, color='y', width=barWidth, label='2035')\n", + "plt.bar(r5, y2040_TotActCap_CE.vCEActCap, color='c', width=barWidth, label='2040')\n", + "plt.bar(r6, y2045_TotActCap_CE.vCEActCap, color='m', width=barWidth, label='2045')\n", + "plt.bar(r7, y2050_TotActCap_CE.vCEActCap, color='k', width=barWidth, label='2050')\n", + "\n", + "# Add xticks on the middle of the group bars\n", + "plt.xlabel('Technologies', fontweight='bold')\n", + "plt.xticks([r + barWidth for r in range(len(y2020_TotActCap_CE))], y2020_TotActCap_CE.index, rotation=90)\n", + "plt.ylabel('Capacity [GW]')\n", + "plt.title('Active Capacity by Year and Technology')\n", + "plt.grid()\n", + "# Create legend & Show graphic\n", + "plt.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sCEsYearvCETotCapvCENewCapvCEDecCapvCEActCapvCEHibCapvInvCostCEvCEDeltaActCapvEmiCO2CEvEmiSOxCEvEmiPM25CE
112sCESOPHVCEWTy202026.17535713.9601573.05380026.1753570.06.6049440.00.00.00.0
113sCESOPHVCEWTy202539.09930815.9777513.05380039.0993080.04.8998910.00.00.00.0
114sCESOPHVCEWTy203048.70625812.6607503.05380048.7062580.02.5358660.00.00.00.0
115sCESOPHVCEWTy2035112.50000066.8475423.053800112.5000000.08.5358830.00.00.00.0
116sCESOPHVCEWTy2040125.00000015.5538003.053800125.0000000.01.3101820.00.00.00.0
117sCESOPHVCEWTy2045137.50000026.46015713.960157137.5000000.01.4956840.00.00.00.0
118sCESOPHVCEWTy2050150.00000028.47775115.977751150.0000000.01.0495410.00.00.00.0
\n", + "
" + ], + "text/plain": [ + " sCE sYear vCETotCap vCENewCap vCEDecCap vCEActCap \\\n", + "112 sCESOPHVCEWT y2020 26.175357 13.960157 3.053800 26.175357 \n", + "113 sCESOPHVCEWT y2025 39.099308 15.977751 3.053800 39.099308 \n", + "114 sCESOPHVCEWT y2030 48.706258 12.660750 3.053800 48.706258 \n", + "115 sCESOPHVCEWT y2035 112.500000 66.847542 3.053800 112.500000 \n", + "116 sCESOPHVCEWT y2040 125.000000 15.553800 3.053800 125.000000 \n", + "117 sCESOPHVCEWT y2045 137.500000 26.460157 13.960157 137.500000 \n", + "118 sCESOPHVCEWT y2050 150.000000 28.477751 15.977751 150.000000 \n", + "\n", + " vCEHibCap vInvCostCE vCEDeltaActCap vEmiCO2CE vEmiSOxCE vEmiPM25CE \n", + "112 0.0 6.604944 0.0 0.0 0.0 0.0 \n", + "113 0.0 4.899891 0.0 0.0 0.0 0.0 \n", + "114 0.0 2.535866 0.0 0.0 0.0 0.0 \n", + "115 0.0 8.535883 0.0 0.0 0.0 0.0 \n", + "116 0.0 1.310182 0.0 0.0 0.0 0.0 \n", + "117 0.0 1.495684 0.0 0.0 0.0 0.0 \n", + "118 0.0 1.049541 0.0 0.0 0.0 0.0 " + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Lets define a dataset with the characteristics of each CE technology\n", + "# The dataset NAMED CE TECHNOLOGIES will contain the following columns:\n", + "# - sCE: Name of the technology\n", + "# - sYear: Year of the data\n", + "# - vInvCostCE: Investment cost of the technology\n", + "# - vCENewCap: New capacity of the technology\n", + "# - vCETotCap: Total capacity of the technology\n", + "# - vCEDecCap: Decomissioned capacity of the technology\n", + "# - vCEActCap: Actual capacity of the technology\n", + "# - vCEHibCap: Hibernated capacity of the technology\n", + "# - vCEDeltaActCap: Change in actual capacity of the technology\n", + "# - vEmiCO2CE: CO2 emissions of the technology\n", + "# - vEmiSOxCE: SOx emissions of the technology\n", + "# - vEmiPM25CE: PM2.5 emissions of the technology\n", + "\n", + "# Create the dataset\n", + "import pandas as pd\n", + "CE_TECHNOLOGIES = pd.DataFrame(columns=['sCE', 'sYear', 'vCETotCap', 'vCENewCap', 'vCEDecCap', 'vCEActCap', 'vCEHibCap','vInvCostCE' ,'vCEDeltaActCap', 'vEmiCO2CE', 'vEmiSOxCE', 'vEmiPM25CE'])\n", + "\n", + "# Fill the dataset with the data\n", + "CE_TECHNOLOGIES['sCE'] = data_results['vInvCostCE'].sCE\n", + "CE_TECHNOLOGIES['sYear'] = data_results['vInvCostCE'].sYear\n", + "CE_TECHNOLOGIES['vCETotCap'] = data_results['vCETotCap'].vCETotCap\n", + "CE_TECHNOLOGIES['vCENewCap'] = data_results['vCENewCap'].vCENewCap\n", + "CE_TECHNOLOGIES['vCEDecCap'] = data_results['vCEDecCap'].vCEDecCap\n", + "CE_TECHNOLOGIES['vCEActCap'] = data_results['vCEActCap'].vCEActCap\n", + "CE_TECHNOLOGIES['vCEHibCap'] = data_results['vCEHibCap'].vCEHibCap\n", + "CE_TECHNOLOGIES['vInvCostCE'] = data_results['vInvCostCE'].vInvCostCE\n", + "CE_TECHNOLOGIES['vCEDeltaActCap'] = data_results['vCEDeltaActCap'].vCEDeltaActCap\n", + "CE_TECHNOLOGIES['vEmiCO2CE'] = data_results['vEmiCO2CE'].vEmiCO2CE\n", + "CE_TECHNOLOGIES['vEmiSOxCE'] = data_results['vEmiSOxCE'].vEmiSOxCE\n", + "CE_TECHNOLOGIES['vEmiPM25CE'] = data_results['vEmiPM25CE'].vEmiPM25CE\n", + "\n", + "# Lets extract the data for the technology 'sCENUCLEAR' and visualize the results\n", + "CE_TECHNOLOGIES[CE_TECHNOLOGIES['sCE']=='sCESOPHVCEWT']\n" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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t+ZFRUU69y+VdPz4cQCQHq7l6+uLkydP4urVq1KZuLg4qNVqtG7dWva2EhERERHRg8msPVLTpk1D//790bhxY9y+fRsxMTGIj4/H7t27ce7cOel+qbp16+LEiRMIDw+Hn58f2rdvDwAIDAxE69at8fzzz2PhwoVITU3FW2+9hbCwsHJ7nIiIiIiIiEzBrInU1atXMXLkSFy5cgUajQbt27fH7t270bdvX1y6dAl79+7Fhx9+iKysLHh4eCAkJARvvfWW9HoLCwts374d48ePh6+vL+zt7TFq1Cid504RERERERGZmlkTqTVr1lS4zMPDAwkJCfeM4enpiZ07d5qyWURERERERJUy+2ATRERERERkOMWc6h0xT8w261OTapwaN9gEERERERHVfgsWLEDnzp3h6OgIFxcXDB48GCkpKTplcnNzERYWhrp168LBwQEhISHSKNwAcOPGDfTr1w8NGjSAjY0NPDw8MHHixDJDlMfHx+ORRx6BjY0NmjVrhvXr18u+fkykiIiIiIjI5BISEhAWFoakpCTExcVBq9UiMDAQWVlZUpnw8HBs27YNsbGxSEhIwOXLlzFkyBBpuVKpxKBBg/Ddd9/hjz/+wPr167F37168/PLLUpnz588jODgYAQEBOH78OCZPnowXXngBu3fvlnX9eGkfERERERGZ3K5du3Sm169fDxcXFyQnJ8PPzw8ZGRlYs2YNYmJi0KtXLwDAunXr4O3tjaSkJPj4+KBOnToYP368FMPT0xMTJkzAokWLpHkrV66El5cXPvjgAwCAt7c3Dh06hKioKAQFBcm2fuyRIiIiIiIi2WVkZAAAnJ2dAQDJycnQarXo06ePVKZVq1Zo3LgxEhMTy41x+fJlfPPNN+jZs6c0LzExUScGAAQFBVUYw1SYSBERERERkayKioowefJkdO/eHW3btgUApKamwtraGk5OTjplXV1dkZqaqjNv2LBhsLOzQ8OGDaFWq7F69WppWWpqKlxdXcvEyMzMRE5OjjwrBCZSREREREQks7CwMJw6dQpffvmlUa+PiorCsWPHsHXrVpw7dw4REREmbqHheI8UERERERHJZuLEidi+fTsOHjyIRo0aSfPd3NyQn5+P9PR0nV6ptLQ0uLm56cRwc3ODm5sbWrVqBWdnZzz22GOYOXMm3N3d4ebmpjPSX3EMtVoNlUol23qxR4qI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vr6+8PHxAQAEBgaidevWeP7557Fw4UKkpqbirbfeQlhYWLk9TkREREREVD127dqlM71+/Xq4uLggOTkZfn5+yMjIuOco3cVWrFiB9PR0zJo1S+e5swCwcuVKeHl54YMPPgAAeHt749ChQ4iKikJQUJBs62fWROrq1asYOXIkrly5Ao1Gg/bt22P37t3o27cvACAqKgpKpRIhISE6XX3FLCwssH37dowfPx6+vr6wt7fHqFGjMHfuXHOtEhERERERlaP4XjpnZ2cA0GuUbgA4c+YM5s6diyNHjuCvv/4qEzcxMVEnBnB3JO/JkyfLtCZ3mTWRWrNmTaXLbW1tER0djejo6ArLeHp6YufOnaZuGhERERERmUhRUREmT56M7t27o23btgCA1NRUWFtb69zrBACurq5ITU0FcPexRcOGDcOiRYvQuHHjchOp1NTUMvdUubq6IjMzEzk5OWWG6zcVsw82QURERERE97ewsDCcOnUKhw4dMuh106ZNg7e3N5577jmZWma8GjfYBBERERER3T8mTpyI7du348CBA2jUqJE0383NTRqlu6SSo3Tv378fsbGxsLS0hKWlJXr37g0AqFevHmbPni3FKR65u2QMtVotW28UwB4pIiIiIiKSgRACkyZNwpYtWxAfHw8vLy+d5SVH6Q4JCQFQdpTuzZs36wy3f/ToUYwdOxY//PADmjZtCuDuSN6lb/WJi4uTYsiFiRQREREREZlcWFgYYmJisHXrVjg6Okr3PWk0GqhUKr1G6S5Olopdv34dwN2R+YrvrXr55ZexbNkyTJkyBWPHjsX+/fuxadMm7NixQ9b1YyJFRERERFQLCX//cucXFRUhMzMTarXarA/wXbFiBQDAv1Q7161bJz0s916jdOvDy8sLO3bsQHh4OJYsWYJGjRph9erVsg59DjCRIiIiIiIiGQgh7llGn1G6S/L39y83rr+/P3755ReD21gVHGyCiIiIiIjIQEykiIiIiIiIDMREioiIiIiIyEBMpIiIiIiIiAzERIqIiIiIiMhATKSIiIiIiIgMxESKiIiIiIjIQEykiIiIiIiIDMREioiIiIiIyECW5m4AEREREREZLl4RX631+Qv/aq2vpmOPFBERERERmdyCBQvQuXNnODo6wsXFBYMHD0ZKSopOmdzcXISFhaFu3bpwcHBASEgI0tLSyo1348YNNGrU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VCIkJAR5eXkICgrC8uXLpbJWVlaIjo5GeHg4hBBo1qwZFi9ejBdffFEq4+XlhR07diA8PBxLlixBo0aNsHr1almHPgfMnEjda+NaW1tj7969+PDDD5GVlQUPDw+EhITgrbfekspaWFhg+/btGD9+PHx9fWFvb49Ro0bpPHeKiIiIiOh+U9GYcUVFRcjMzIRarTbrpYD6jGlna2uL6OhoREdHl7u8X79+6Nev3z3j+Pv745dffjG4jVVh9kv7KuPh4YGEhIR7xvH09MTOnTtN1SwiIiIiIqJKmfWBvERERERERLUREykiovuBQvHfeOilhiUmIiIi06sRw58TERERUc0Wr4g3dxOIahT2SBERERERERmIiRQRERERUS2gzyh4pJ/ihwpXBS/tIyIiIiKqwaysrKBQKHDt2jXUr18fCoWi0vJFRUXIz89Hbm6uLMOfyx1fTkII5Ofn49q1a1AqlbC2tjY6FhMpIiIiIqIazMLCAo0aNcI///yDv//++57lhRDIycmBSqW6Z9JlDLnjVwc7Ozs0bty4SokgEykiIiIiohrOwcEBzZs3h1arvWdZrVaLgwcPws/PD1ZWViZvi9zx5WZhYQFLS8sqJ4FMpIiIiIiIagELCwtYWFjoVa6goAC2trayJDpyx68tatdFjURERERERDUAEykiIiIiIiIDMZEiIiIiIiIykN73SBUUFKCwsBA2NjbSvLS0NKxcuRJZWVl44okn0KNHD1kaSUREREREVJPonUi9+OKLsLa2xscffwwAuH37Njp37ozc3Fy4u7sjKioKW7duxYABA2RrLBERERERUU2g96V9P/74I0JCQqTpDRs2oLCwEH/++Sd+/fVXREREYNGiRbI0koiIiIiIqCbRO5H6999/0bx5c2l63759CAkJgUajAQCMGjUKp0+fNn0LiYiIiIiIahi9EylbW1vk5ORI00lJSejatavO8jt37pi2dURERERERDWQ3olUhw4d8NlnnwEAfvjhB6SlpaFXr17S8nPnzqFBgwambyERERGRmSgUun9ERMX0Hmxi1qxZ6N+/PzZt2oQrV65g9OjRcHd3l5Zv2bIF3bt3l6WRRERERERENYneiVTPnj2RnJyMPXv2wM3NDU8//bTO8g4dOqBLly4mbyAREREREVFNo3ciNXbsWCxZsgSvvvpqucvHjRtnskYRERERERHV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lztfrVajTp06JmsQERERERFRTad3IuXp6SlnO4iIiIiIiGoNkw02QURERERE9KBgIkVERERERGQgJlJEREREREQG0juROnjwIAoKCuRsCxERERERUa2gdyIVEBCAmzdvytkWIiIiIiKiWkHvRKq850cRERERERE9iAy6R0qhUMjVDiIiIiIiolpD7+dIAcDo0aNhY2NTaZlvvvmmSg0iIiIiIiKq6QxKpBwdHaFSqeRqCxERERERUa1gUCK1dOlSuLi4yNUWIiIiIiKiWkHve6R4fxQREREREdFdHLWPiIiIiIjIQHonUgcOHICzs7OcbSEiIiIiIqoV9E6krK2tsWvXLp15GzZsgJeXF1xcXDBu3Djk5eWZvIFEREREREQ1jd6J1Ny5c3H69Glp+uTJkwgNDUWfPn0wdepUbNu2DQsWLJClkURERERERDWJ3onU8ePH0bt3b2n6yy+/RNeuXfHJJ58gIiICS5cuxaZNm2RpJBERERERUU2idyJ169YtuLq6StMJCQno37+/NN25c2dcunTJtK0jIiIiIiKqgfROpFxdXXH+/HkAQH5+Po4dOwYfHx9p+e3bt2FlZWX6FhIREREREdUweidSAwYMwNSpU/HDDz9g2rRpsLOzw2OPPSYtP3HiBJo2bSpLI4mIiIiIiGoSS30Lzps3D0OGDEHPnj3h4OCATz/9FNbW1tLytWvXIjAwUJZGEhERERER1SR6J1L16tXDwYMHkZGRAQcHB1hYWOgsj42NhYODg8kbSEREREREVNPonUgV02g05c7nw3qJiIiIiOhBofc9UkRERERERHQXEykiIiIiIiIDMZEiIiIiIiIyEBMpIiIiIiIiAzGRIiIiIiIiMpDBo/YRERER0f1PER+vM33APM0gqrHYI0VERERERGQgJlJEREREREQGYiJFRERERERkICZSREREREREBjJrInXw4EEMHDgQDRo0gEKhwLfffquzfPTo0VAoFDp//fr10ylz8+ZNjBgxAmq1Gk5OTggNDcWdO3eqcS2IiIiIiOhBY9ZEKisrCw8//DCio6MrLNOvXz9cuXJF+vviiy90lo8YMQKnT59GXFwctm/fjoMHD2LcuHFyN52IiIiIiB5gZh3+vH///ujfv3+lZWxsbODm5lbust9++w27du3C0aNH8eijjwIAPvroIwwYMADvv/8+GjRoUO7r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onHjxmLkyJEiLy9PTJgwQSgUCqFUKoWfn1+5dRti4sSJYtu2bUIIIS5duiRatWolLCwshKurq7CwsBDt2rWr8rF35coV8fzzzwuNRiOUSqVQKpXCyclJjBkzRqSmplYpttznutLvUbkUFhaKNWvWiODgYNGmTRvRtm1bMXDgQPHpp59W6T0qhPzna4VCUS3bqDZiIlUD/f3332L27NnCy8tLKJVKERAQIDZu3Chyc3OrHLv0weDo6GjyZO3VV18VU6dOlaYdHBzEwoULxfr168X69etF//79xUsvvWR0/MGDB4uZM2dK03/99ZdQqVQiMDBQvPLKK8LBwUFERUUZHf/gwYNizJgxwtHRUdjb24uRI0dW6YOytNL7wMHBweT74OLFi2LOnDnioYcekj6MN2zYYLKkWe51KCwsFM8884xQKBSiZcuWYtCgQWLQoEGiRYsWQqlUimeffbbKHzxCCJGYmChCQ0OFWq0Wbdu2FRYWFibb13l5eaJTp07CxsZGDB48WEydOlW8+eab4oknnhDW1tbCx8dH50usobKzs8Wnn34q/P39hVKpFE2aNBFz584VFy9eNEn774fjoNiBAwfEyJEjhb29vVCr1eKFF14QSUlJVY4r9/k0IyNDPP3008LW1la4uLiImTNnioKCAml5amqqUCqVRsfv2bOn9MPEoUOHhI2NjWjfvr149tlnRceOHYWdnZ04fPhwldZB7v38zTffCEtLS2FtbS1sbGzEp59+KmxtbUW/fv1EcHCwsLS0FO+++67R8QcOHCgWL15c4fIlS5aIwYMHGx1/4sSJolWrVmLp0qXC399fDBo0SLRt21YcOnRIJCQkiNatW4vp06cbHV8IIVxdXcXJkyeFEEI888wzok+fPuLatWtCCCFu3LghHn/8cfHUU08ZHT8jI0N4eXmJ+vXri8mTJ4uVK1eKFStWiEmTJol69eqJ5s2bi9u3bxsdX+5zXXUkCUVFRSI4OFgoFArRoUMHMXToUPHss8+K9u3bC4VCIQYNGlSl+NVxvr569arJ4t1PmEjVcPv27RMjRowQdnZ2ok6dOmLChAni559/NjpedXx5adu2rU6PUek64uPjRbNmzYyO36hRI50P93nz5omHH35Yml69erXOtLHu3Lkj1q5dK/z8/IRCoRDNmzcX7777rrhy5UqV4lbnF0ghhNi/f7/0JVKj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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# vTotalCapST\n", + "y2020_TotCap_ST = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2020') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSOTH_RES'))].groupby('sST').sum().vSTTotCap\n", + "y2025_TotCap_ST = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2025') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSOTH_RES'))].groupby('sST').sum().vSTTotCap\n", + "y2030_TotCap_ST = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2030') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSOTH_RES'))].groupby('sST').sum().vSTTotCap\n", + "y2035_TotCap_ST = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2035') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSOTH_RES'))].groupby('sST').sum().vSTTotCap\n", + "y2040_TotCap_ST = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2040') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSOTH_RES'))].groupby('sST').sum().vSTTotCap\n", + "y2045_TotCap_ST = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2045') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSOTH_RES'))].groupby('sST').sum().vSTTotCap\n", + "y2050_TotCap_ST = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2050') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSOTH_RES'))].groupby('sST').sum().vSTTotCap\n", + "\n", + "\n", + "# Create a figure and a set of subplots\n", + "fig, ax = plt.subplots(1, 1, figsize=(10, 5))\n", + "\n", + "# Set the bar width\n", + "barWidth = 0.15\n", + "\n", + "# Set the position of the bars on the x-axis\n", + "r1 = np.arange(len(y2020_TotCap_ST))\n", + "r2 = [x + barWidth for x in r1]\n", + "r3 = [x + barWidth for x in r2]\n", + "r4 = [x + barWidth for x in r3]\n", + "r5 = [x + barWidth for x in r4]\n", + "r6 = [x + barWidth for x in r5]\n", + "r7 = [x + barWidth for x in r6]\n", + "r8 = [x + barWidth for x in r7]\n", + "r9 = [x + barWidth for x in r8]\n", + "\n", + "# Make the plot\n", + "plt.bar(r1, y2020_TotCap_ST, color='b', width=barWidth, label='2020')\n", + "plt.bar(r2, y2025_TotCap_ST, color='r', width=barWidth, label='2025')\n", + "plt.bar(r3, y2030_TotCap_ST, color='g', width=barWidth, label='2030')\n", + "plt.bar(r4, y2035_TotCap_ST, color='y', width=barWidth, label='2035')\n", + "plt.bar(r5, y2040_TotCap_ST, color='c', width=barWidth, label='2040')\n", + "plt.bar(r6, y2045_TotCap_ST, color='m', width=barWidth, label='2045')\n", + "plt.bar(r7, y2050_TotCap_ST, color='k', width=barWidth, label='2050')\n", + "\n", + "\n", + "# Add xticks on the middle of the group bars\n", + "plt.xlabel('Technologies', fontweight='bold')\n", + "plt.xticks([r + barWidth for r in range(len(y2020_TotCap_ST))], y2020_TotCap_ST.index, rotation=90)\n", + "plt.ylabel('ST UNITS')\n", + "plt.title('Total Capacity by Technology and Year')\n", + "# Create legend & Show graphic\n", + "plt.legend()\n", + "plt.grid()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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UfePiRQRERERERnckiVLADx6duzjoqOjMXjwYABAVFQUFAoF+vTpg5ycHISEhGDx4sXythYWFli0aBEiIiIghEC9evUwb948vPvuu/I2Xl5e2LZtGyIiIrBgwQLUqlULy5YtM+rU5wATKSIiIiKiSunxKcAfp1arkZmZCXt7eygUpruTp6T2Pc7a2hqLFi3CokWLii1/+eWXNR7EW5LAwEAcO3ZM6zbqg/dIERERERERaYmJFBERERERkZaYSBEREREREWmJiRQREREREZGWmEgRERERERFpiYkUEREREVElUJZZ8Khs1Gq13jE4/TkRERERUQVmYWEBSZJw69YtVK9eHZIklbq9Wq1Gbm4usrOzjTL9ubHjG5MQArm5ubh16xYUCgUsLS11jsVEioiIiIioAjMzM0OtWrXw77//4vLly0/cXgiBrKwsKJXKJyZdujB2/PJgY2MDT09PvRJBJlJERERERBWcra0t6tevD5VK9cRtVSoV9uzZg4CAAFhYWBi8LcaOb2xmZmYwNzfXOwlkIkVEREREVAmYmZnBzMysTNvl5eXB2traKImOseNXFpVrUCMREREREVEFwESKiIiIiIhIS0ykiIiIiIiItFTme6Ty8vKQn58PKysreV1aWhqWLl2KBw8eoEePHmjbtq1RGklERERERFSRlDmRevfdd2FpaYlvvvkGAHDv3j34+voiOzsb7u7uiIqKwqZNm9C1a1ejNZaIiIiIiKgiKHMitX//fnz99dfy8vfff4/8/HycP38eDg4OGD9+PL744gsmUkRERERPASkxUWM5wTTNIKqwynyP1LVr11C/fn15edeuXejTpw8cHBwAAIMGDcLp06cN30IiIiIiIqIKpsyJlLW1NbKysuTlgwcPolWrVhrl9+/fN2zriIiIiIiIKqAyJ1LNmjXDDz/8AADYu3cv0tLS0LFjR7n84sWLqFGjhuFbSEREREREVMGU+R6pKVOmoEuXLli3bh1u3LiBwYMHw93dXS7fsGED/P39jdJIIiIiIiKiiqTMiVT79u2RnJyM33//HW5ubujbt69GebNmzdCyZUuDN5CIiIiIiKiiKXMiNXToUCxYsABjx44ttnz48OEGaxQREREREVFFVuZ7pFatWqUx2QQREREREdGzqsyJlBDCmO0gIiIiIiKqNMo8tA8A7t27B2tr61K3sbe316tBREREREREFZ1WiVSDBg1KLBNCQJIk5Ofn690oIiIiIiKiikyrROrnn3+Gk5OTsdpCRERERERUKWiVSPn7+8PFxcVYbSEiIiIiIqoUyjzZBBERERERET1S5kSqdu3aMDMzM2ZbiIiIiIiIKoUyJ1KXLl1CtWrVjNmWIvLz8zF58mR4eXlBqVSibt26+OSTTzSmYhdCYMqUKXB3d4dSqURQUBDOnz9fru0kIiIiIqJnS5nvkXrxxRfLtN3Ro0d1bkxhn332GZYsWYJVq1ahUaNG+OOPPzBkyBA4ODjgvffeAwB8/vnnWLhwIVatWgUvLy9MnjwZISEhOHPmzBOnaiciIiIiItJFmROpnj17GrMdxTpw4AB69uyJbt26AQDq1KmDNWvW4PDhwwAe9UbNnz8fH3/8sdy+77//Hq6urti4cSPeeOONcm8zERERERE9/cqcSE2dOtWY7ShWmzZt8O233+LcuXNo0KABTpw4gX379mHevHkAHg03TE1NRVBQkPwaBwcHtGrVCklJSSUmUjk5OcjJyZGXMzMzAQAqlQoqlcqIe6SbgjYZs23GroPxTV8H45u+DsY3fR2Mb/o6GN/0dZQ1vvKxWykAQCgfK4NSo+zxWBWl/RW5Dsav2Mq6X5IQhc6SCkStVmPSpEn4/PPPYWZmhvz8fMycORMTJ04E8KjHyt/fH9evX4e7u7v8un79+kGSJKxdu7bYuNOmTcP06dOLrI+JiYGNjY1xdoaIiIiIiCq8hw8f4s0330RGRgbs7e1L3K7MPVIdOnSAJEmlbiNJEnbt2lX2Vj7BunXrsHr1asTExKBRo0Y4fvw4wsPDUaNGDQwaNEjnuBMnTkRkZKS8nJmZCQ8PDwQHB5f6ZpmKSqVCXFwcOnfuDAsLi0pZB+Obvg7GN30djG/6Ohjf9HUwvunrKGt8h337NJa3dfvfv7uhm0ZZRkaG1vF19Swdg2c1vqkVjFZ7kjInUs2aNSux7N69e4iJidEYLmcIH374ISZMmCAP0WvSpAn++ecfzJ49G4MGDYKbmxsAIC0tTaNHKi0trdT2WllZwcrKqsh6CwuLCv3LUB7tM3YdjG/6Ohjf9HUwvunrYHzT18H4pq/jSfGzCn2BLmU9VoYsjbLi4pi6/ZWhDsavmMq6T2VOpKKiooqsy8vLw6JFizBz5kzUrFkTn3zySdlbWAYPHz6EQqE5Q7uZmRnUajUAwMvLC25ubti1a5ecOGVmZuLQoUMYNWqUQdtCRERERERUoMyJVGGrV6/GlClTkJWVhWnTpmH48OEwN9c5XLG6d++OmTNnwtPTE40aNcKxY8cwb948DB06FMCjoYTh4eH49NNPUb9+fXn68xo1aqBXr14GbQsREREREVEBrTOf7du3Y8KECbh06RI++OADREZGokqVKsZoG7766itMnjwZo0ePxs2bN1GjRg2MGDECU6ZMkbcZN24cHjx4gOHDhyM9PR1t27bF9u3b+QwpIiIiIiIymjInUocPH8b48eNx8OBBjBw5Ejt37oSzs7Mx2wY7OzvMnz8f8+fPL3EbSZIwY8YMzJgxw6htISIiIiIiKlDmRKp169ZQKpUYOXIkvLy8EBMTU+x27733nsEaR0REREREVBGVOZHy9PSEJEnYuHFjidtIksREioiIiIiInnplTqQuX75sxGYQERERERFVHoonb0JERERERESPK3OPVGRkZLHrHRwc0KBBA/Tu3bvYh9wSERERERE9bcqcSB07dqzY9enp6bhw4QImT56M+Ph4eHp6GqxxREREREREFVGZE6mEhIQSyzIzMzFgwABMmDChxNn8iIiIiIiInhYGuUfK3t4ekydPxv79+w0RjoiIiIiIqEIz2GQTzs7OuHPnjqHCERERERERVVgGS6QOHjyIunXrGiocERERERFRhVXme6T+/PPPYtdnZGQgOTkZs2bNwtSpUw3WMCIiIiIiooqqzIlUs2bNIEkShBBFypydnREZGYnRo0cbtHFEREREREQVUZkTqUuXLhW73t7eHlWrVjVYg4iIiIiIiCq6MidStWvXNmY7iIiIiIiIKg2DTTZBRERERET0rGAiRUREREREpCUmUkRERERERFoqcyK1Z88e5OXlGbMtRERERERElUKZE6kOHTrgzp07xmwLERERERFRpVDmRKq450cRERERERE9i7S6R0qSJGO1g4iIiIiIqNIo83OkAGDw4MGwsrIqdZtffvlFrwYRERERERFVdFolUnZ2dlAqlcZqCxERERERUaWgVSK1cOFCuLi4GKstRERERERElUKZ75Hi/VFERERERESPcNY+IiIiIiIiLZU5kUpISICTk5Mx20JERERERFQplDmRsrS0xPbt2zXWff/99/Dy8oKLiwuGDx+OnJwcgzeQiIiIiIio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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# vTotalCapST\n", + "y2020_TotCap_ST = data_results['vSTNewCap'][(data_results['vSTNewCap'].sYear=='y2020') & (data_results['vSTNewCap'].sST.str.startswith('sST_DSOTH_RES'))].groupby('sST').sum().vSTNewCap\n", + "y2025_TotCap_ST = data_results['vSTNewCap'][(data_results['vSTNewCap'].sYear=='y2025') & (data_results['vSTNewCap'].sST.str.startswith('sST_DSOTH_RES'))].groupby('sST').sum().vSTNewCap\n", + "y2030_TotCap_ST = data_results['vSTNewCap'][(data_results['vSTNewCap'].sYear=='y2030') & (data_results['vSTNewCap'].sST.str.startswith('sST_DSOTH_RES'))].groupby('sST').sum().vSTNewCap\n", + "y2035_TotCap_ST = data_results['vSTNewCap'][(data_results['vSTNewCap'].sYear=='y2035') & (data_results['vSTNewCap'].sST.str.startswith('sST_DSOTH_RES'))].groupby('sST').sum().vSTNewCap\n", + "y2040_TotCap_ST = data_results['vSTNewCap'][(data_results['vSTNewCap'].sYear=='y2040') & (data_results['vSTNewCap'].sST.str.startswith('sST_DSOTH_RES'))].groupby('sST').sum().vSTNewCap\n", + "y2045_TotCap_ST = data_results['vSTNewCap'][(data_results['vSTNewCap'].sYear=='y2045') & (data_results['vSTNewCap'].sST.str.startswith('sST_DSOTH_RES'))].groupby('sST').sum().vSTNewCap\n", + "y2050_TotCap_ST = data_results['vSTNewCap'][(data_results['vSTNewCap'].sYear=='y2050') & (data_results['vSTNewCap'].sST.str.startswith('sST_DSOTH_RES'))].groupby('sST').sum().vSTNewCap\n", + "\n", + "\n", + "# Create a figure and a set of subplots\n", + "fig, ax = plt.subplots(1, 1, figsize=(10, 5))\n", + "\n", + "# Set the bar width\n", + "barWidth = 0.15\n", + "\n", + "# Set the position of the bars on the x-axis\n", + "r1 = np.arange(len(y2020_TotCap_ST))\n", + "r2 = [x + barWidth for x in r1]\n", + "r3 = [x + barWidth for x in r2]\n", + "r4 = [x + barWidth for x in r3]\n", + "r5 = [x + barWidth for x in r4]\n", + "r6 = [x + barWidth for x in r5]\n", + "r7 = [x + barWidth for x in r6]\n", + "r8 = [x + barWidth for x in r7]\n", + "r9 = [x + barWidth for x in r8]\n", + "\n", + "# Make the plot\n", + "plt.bar(r1, y2020_TotCap_ST, color='b', width=barWidth, label='2020')\n", + "plt.bar(r2, y2025_TotCap_ST, color='r', width=barWidth, label='2025')\n", + "plt.bar(r3, y2030_TotCap_ST, color='g', width=barWidth, label='2030')\n", + "plt.bar(r4, y2035_TotCap_ST, color='y', width=barWidth, label='2035')\n", + "plt.bar(r5, y2040_TotCap_ST, color='c', width=barWidth, label='2040')\n", + "plt.bar(r6, y2045_TotCap_ST, color='m', width=barWidth, label='2045')\n", + "plt.bar(r7, y2050_TotCap_ST, color='k', width=barWidth, label='2050')\n", + "\n", + "\n", + "# Add xticks on the middle of the group bars\n", + "plt.xlabel('Technologies', fontweight='bold')\n", + "plt.xticks([r + barWidth for r in range(len(y2020_TotCap_ST))], y2020_TotCap_ST.index, rotation=90)\n", + "plt.ylabel('ST UNITS')\n", + "plt.title('New Capacity ST Res Year')\n", + "# Create legend & Show graphic\n", + "plt.legend()\n", + "plt.grid()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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5EgEBASgVatWAB53sevQoQOCg4MREREhxbCxsUGVKlUAAHPnzoWfnx/q16+PzMxMLF26FPHx8di1a5es68ciiYiIiIiISmTRokUAgMDAQL35K1aswODBgwEAUVFRUCqV6N27N7KyshAcHIyFCxdKy/7444+4ffs21qxZgzVr1kjza9SogcuXLwMAsrOzMWrUKFy/fh2Ojo5o1KgRdu/ejaCgIFnXj0USEREREZE1EqLIptzcXKSlpUGtVkOpNP8VNKKY3PI4ODggOjoa0dHRhbZHRkYiMjKy2BijR4/G6NGjjUmxVHhNEhERERERkQ4WSURERERERDpYJBEREREREelgkURERERERKSDRRIREREREZEOFklEREREREQ6WCQRERERERHpYJFERERERESkg0USERERERGRDhZJREREREREOipYOgEiIiIiIipIMVlhttcSk0SJlp8xYwY2bNiAs2fPQqVSoXXr1pg5cybq1q0rLZOZmYlRo0Zh3bp1yMrKQnBwMBYuXAhPT08AwN27dzFgwACcOHECd+/ehYeHB3r06IHp06dDrVZLcRISEhAREYHTp0/Dx8cHEyZMwODBg02y3kXhmSQiIiIiIiqRffv2ISQkBImJiYiLi4NWq0WXLl2Qnp4uLRMeHo6tW7ciNjYW+/btw40bN9CrVy+pXalUokePHtiyZQv++usvrFy5Ert378bw4cOlZS5duoRu3bohKCgIx44dQ1hYGN5++23s3LlT1vXjmSQiIiIiIiqRHTt26E2vXLkSHh4eSEpKQrt27aDRaLBs2TLExMSgQ4cOAIAVK1agXr16SExMRKtWrVCpUiW8//77UowaNWpgxIgRmDVrljRv8eLF8PPzw+zZswEA9erVw4EDBxAVFYXg4GDZ1o9nkoiIiIiIqFQ0Gg0AwM3NDQCQlJQErVaLTp06Scv4+/vD19cXhw4dKjTGjRs3sGHDBrRv316ad+jQIb0YABAcHFxkDFNhkUREREREREbLzc1FWFgY2rRpgwYNGgAAkpOTYWdnB1dXV71lPT09kZycrDevX79+cHR0RLVq1aBWq7F06VKpLTk5WbqGSTdGWloaMjIy5FkhsEgiIiIiIqJSCAkJwalTp7Bu3Tqjnh8VFYWjR49i8+bNuHDhAiIiIkycYcnxmiQiIiIiIjJKaGgotm3bhv3796N69erSfC8v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IiIiIqOFhITg1KlTWLdunVHPj4qKwtGjR7F582ZcuHABERERUlvdunXx3nvvoVmzZmjdujWWL1+O1q1bIyoqylTpF8rqRrcjIiIiIqKyITQ0FNu2bcP+/ftRvXp1ab6Xlxeys7ORmpqqdzYpJSWlwKh0Xl5e8PLygr+/P9zc3PDiiy9i4sSJRY5o3aJFCxw4cECW9cnDM0lERERERFQiQgiEhoZi48aNiI+Ph5+fn157s2bNYGtriz179kjzzp07h6tXryIgIKDIuHn3aCrqlkDA49sCyX1LIJ5JIiIiIiKiEgkJCUFMTAw2b94MZ2dn6TojFxcXqFQquLi4YNiwYYiIiICbmxvUajVGjhyJgIAAadCGn376CSkpKWjevDkqVqyI06dP4+OPP0abNm1Qs2ZNAMDcuXPh5+eH+vXrIzMzE0uXLkV8fDx27dol6/qxSCIiIiIiskLF3eA1NzcXaWlpUKvVUCrN3zls0aJFAIDAwEC9+StWrMDgwYMBPL7WSKlUonfv3no3k82jUqnwzTffIDw8HFlZWfDx8UGvXr0wduxYaZns7GyMGjUK169fh6OjIxo1aoTdu3cXeoNZU2KRREREREREJSJE0QVcHgcHB0RHRyM6OrrQ9qCgIBw8eLDYGKNHj8bo0aONyrE0eE0SERERERGRDhZJREREREREOlgkERERERER6WCRREREREREpINFEhERERERkQ4WSURERERERDpYJBEREREREelgkURERERERKSDRRIREREREZEOFklEREREREQ6Klg6ASIiIiIiKkiRkGC21xKBgSVafsaMGdiwYQPOnj0LlUqF1q1bY+bMmahbt660TGZmJkaNGoV169YhKysLwcHBWLhwITw9PQvEu3v3Lho3bozr16/j3r17cHV1ldoSEhIQERGB06dPw8fHBxMmTMDgwYONXFPD8EwSERERERGVyL59+xASEoLExETExcVBq9WiS5cuSE9Pl5YJDw/H1q1bERsbi3379uHGjRvo1atXofGGDRuGRo0aFZh/6dIldOvWDUFBQTh27BjCwsLw9ttvY+fOnbKtG8AzSUREREREVEI7duzQm165ciU8PDyQlJSEdu3aQaPRYNmyZYiJiUGHDh0AACtWrEC9evWQmJiIVq1aSc9dtGgRUlNT8emnn+Lnn3/Wi7t48WL4+flh9uzZAIB69erhwIEDiIqKQnBwsGzrxzNJRERERERUKhqNBgDg5uYGAEhKSoJWq0WnTp2kZfz9/eHr64tDhw5J886cOYMpU6Zg1apVUCoLliaHDh3SiwEAwcHBejHkwCKJiIiIiIiMlpubi7CwMLRp0wYNGjQAACQnJ8POzk7v2iIA8PT0RHJyMgAgKysL/fr1w6xZs+Dr61to7OTk5ALXMHl6eiItLQ0ZGRmmX5n/x+52RERERERktJCQEJw6dQoHDhwo0fPGjRuHevXq4c0335QpM+PxTBIRERERERklNDQU27Ztw969e1G9enVpvpeXF7Kzs5Gamqq3fEpKCry8vAAA8fHxiI2NRYUKFVChQgV07NgRAODu7o5JkyZJcVJSUgrEUKvVUKlUsq0XzyQREREREVGJCCEwcuRIbNy4EQkJCfDz89Nrb9asGWxtbbFnzx707t0bAHDu3DlcvXoVAQEBAID169frdZk7cuQIhg4dil9++QW1atUCAAQEBOCnn37Six0XFyfFkAuLJCIiIiIiKpGQkBDExMRg8+bNcHZ2lq4zcnFxgUqlgouLC4YNG4aIiAi4ublBrVZj5MiRCAgIkEa2yyuE8ty5cwfA4xHs8q5lGj58OBYsWIDRo0dj6NChiI+Pxw8//IDt27fLun4skoiIiIiIrFBxN3jNzc1FWloa1Gp1oaPCyW3RokUAgMB8Oa5YsUK60WtUVBSUSiV69+6tdzPZkvDz88P27dsRHh6OefPmoXr16li6dKmsw38DLJKIiIiIiKiEhBBPXMbBwQHR0dGIjo42KGZgYGChcQMDA/HHH3+UOMfS4MANREREREREOlgkERERERER6WCRREREREREpINFEhERERERkQ4WSURERERERDosWiQtWrQIjRo1glqthlqtRkBAAH7++WepPTMzEyEhIahcuTIqVqyI3r17F7jjLhERERERkSlZtEiqXr06Pv/8cyQlJeH3339Hhw4d0KNHD5w+fRoAEB4ejq1btyI2Nhb79u3DjRs30KtXL0umTERERERETzmL3iepe/fuetPTpk3DokWLkJiYiOrVq2PZsmWIiYlBhw4dADy+OVW9evWQmJgo3amXiIiIiIjIlKzmZrI5OTmIjY1Feno6AgICkJSUBK1Wi06dOknL+Pv7w9fXF4cOHSqySMrKykJWVpY0nZaWBgDQarXQarXyroQR8nKSKzc54zN3y8Rn7uaPLXd85m6Z+Mzd/LHljs/cH1Op8scuO7mbO741xNZqtRBCIDc3F7m5uQbHz7vpat5zTUnO2OaQm5sLIQS0Wi1sbGz02gx9rxXCkNvlyujkyZMICAhAZmYmKlasiJiYGLz88suIiYnBkCFD9AoeAGjRogWCgoIwc+bMQuNFRkZi8uTJBebHxMTA0dFRlnUgIiIiIjJGhQoV4OXlBR8fH9jZ2Vk6nadCdnY2rl27huTkZDx69Eiv7eHDh+jfvz80Gg3UanWRMSx+Jqlu3bo4duwYNBoNfvzxR7z11lvYt2+f0fHGjRuHiIgIaTotLQ0+Pj7o0qVLsRvCUrRaLeLi4tC5c2fY2tqWqfjM3TLxmbv5Y8sdn7lbJj5zN39sueMz98dcXPSnNZqyk7u541tD7MzMTFy7dg0VK1aEg4ODXtt+m/0mzak47XLaSf8XQuD+/ftwdnaGQqEodPnPP/8cGzduxNmzZ6FSqRAQEIDPP/8cdevWlZbJzMzERx99hO+//x5ZWVno0qULoqOj4enpWSDe3bt30bRpU1y/fh13796Fq6srACAhIQEdO3YssPz169fh5eVVaG6ZmZlQqVRo165dgW2a18vsSSxeJNnZ2aF27doAgGbNmuHIkSOYN28e/ve//yE7OxupqanSRgKAlJSUIjcIANjb28Pe3r7AfFtbW1k+uKYid35yxmfulonP3M0fW+74zN0y8Zm7+WPLHb+8556RkT+maeMXpbxvd2Nj5+TkQKFQQKlUQqm03Jhquq+d18UuL6/C7N+/HyEhIWjevDkePXqE8ePH46WXXsKZM2fg5OQEABg1ahS2b9+O2NhYuLi4IDQ0FH369MGvv/5aIN4777yDRo0a4fr163rbIu/fc+fO6Z3w8PDwKDI3pVIJhUJR6LY39H22eJGUX25uLrKystCsWTPY2tpiz5496N27N4DHG+fq1asICAiwcJZEREREROXXjh079KZXrlwJDw8PJCUloV27dtBoNAYPwrZo0SKkpqbi008/1bsdkC4PDw+9Eydys2iRNG7cOHTt2hW+vr64f/8+YmJikJCQgJ07d8LFxQXDhg1DREQE3NzcoFarMXLkSAQEBHBkOyIiIiIiK6LRaAAAbm5uAGDwIGxnzpzBlClT8Ntvv+HixYtFxm/SpAmysrLQoEEDREZGok2bNjKujYWLpFu3bmHQoEG4efMmXFxc0KhRI+zcuROdO3cGAERFRUGpVKJ3797IyspCcHAwFi5caMmUiYiIiIhIR25uLsLCwtCmTRs0aNAAAJCcnAw7O7sCZ388PT2RnJwM4PGo1P369cOsWbPg6+tbaJHk7e2NxYsX44UXXkBWVhaWLl2KwMBA/Pbbb3j++edlWyeLFknLli0rtt3BwQHR0dGIjo42U0ZERERERFQSISEhOHXqFA4cOFCi540bNw716tXDm2++WeQydevW1RsMonXr1rhw4QKioqKwevVqo3N+EstdHUZERERERGVaaGgotm3bhr1796J69erSfC8vL2kQNl26g7DFx8cjNjYWFSpUQIUKFaRR7Nzd3TFp0qQiX7NFixY4f/686VdGh9UN3EBERERERNZNCIGRI0di48aNSEhIgJ+fn167IYOwrV+/Hhk6wzEeOXIEQ4cOxS+//IJatWoV+drHjh2Dt7e3DGv1HxZJRERERERUIiEhIYiJicHmzZvh7OwsXWfk4uIClUpl0CBs+QuhO3fuAADq1asnXcs0d+5c+Pn5oX79+sjMzMTSpUsRHx+PXbt2ybp+LJKIiIiIiKxQoAgssi03NxdpaWlQq9UWub/SokWLAACBgYF681esWIHBgwcDMM0gbNnZ2Rg1ahSuX78OR0dHNGrUCLt370ZQUJApVqNILJKIiIiIiKhEhBBPXKakg7AFBgYWiDt69GiMHj3aqBxLgwM3EBERERER6WCRREREREREpINFEhERERERkQ4WSURERERERDpYJBERERE9zRQKwMXF0lkQlSkskoiIiIiIiHSwSCIiIiIiItLBIomIiIiIiEgHiyQiIiIiIiIdLJKIiIiIiKhEZsyYgebNm8PZ2RkeHh7o2bMnzp07p7dMZmYmQkJCULlyZVSsWBG9e/dGSkqK3jIKhaLAY926dXrLJCQk4Pnnn4e9vT1q166NlStXyr16LJKIiIiIiKxRYQVE3sPGxgaVKlWCjY1NscsZ+iipffv2ISQkBImJiYiLi4NWq0WXLl2Qnp4uLRMeHo6tW7ciNjYW+/btw40bN9CrV68CsVasWIGbN29Kj549e0ptly5dQrdu3RAUFIRjx44hLCwMb7/9Nnbu3GnUNjVUBVmjExERERHRU2fHjh160ytXroSHhweSkpLQrl07aDQaLFu2DDExMejQoQOA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6tUAgF9++QUpKSno0KGD1H7hwgVUrVq1RC++aNEiaDQaBAYGwtvbW3p8//33AAA7Ozvs3r0bXbp0gb+/P0aNGoXevXtj69atJXodIiIiIiIiQxl8TdKnn36Krl274ocffsDNmzcxePBgvS5vGzduRJs2bUr04k8aM8LHxwf79u0rUUwiIiIiIqLSMLhIat++PZKSkrBr1y54eXnh9ddf12tv0qQJWrRoYfIEiYiIiIiIzMngImno0KGYN28ePvzww0Lb3333XZMlRUREREREZCkGX5P07bff6g3cQERERERE9DQyuEgy8J6zREREREREZZrB3e0A4P79+3BwcCh2meLuXEtERERERGTtSlQkPfvss0W2CSGgUCiQk5NT6qSIiIiIiIgspURF0o8//gg3Nze5ciEiIiIiIrK4EhVJbdq0gYeHh1y5EBERERERWZzBAzcQERERERGVBwYXSTVq1ICNjY2cuRAREREREVmcwd3tLl26JGceREREREREVsHgIun55583aLmjR48anQwREREREZGlGVwk9ejRQ848iIiIiIiIrILBRdKkSZPkzIOIiIiIiMgqcHQ7IiIiIiIiHQafSQoKCoJCoSh2GYVCgT179pQ6KSIiIiIiIksxuEhq0qRJkW33799HTEwMsrKyTJETERERERGRxRhcJEVFRRWY9+jRI0RHR2PatGmoVq0apk6datLkiIiIiIiIzM3gIim/7777Dp9++ikyMjIQGRmJd999FxUqGB2OiIiIiIjIKpS4qtmxYwfGjh2LS5cu4aOPPkJERAScnJzkyI2IiIiIiMjsDC6SDh8+jDFjxiAxMRHDhw/H7t274e7uLmduREREREREZmdwkdSqVSuoVCoMHz4cfn5+iImJKXS5Dz74wGTJERERERERmZvBRZKvry8UCgU2bdpU5DIKhYJFEhERERERlWkGF0mXL1+WMQ0iIiIiIiLroLR0AkRERERERNbE4DNJERERhc53cXHBs88+i169esHe3t5kiREREREREVmCwUXSH3/8Uej81NRUnD9/HhMnTkR8fDx8fX1NlhwREREREZG5GVwk7d27t8i2tLQ0DBgwAGPHji1y1DsiIiIiIqKywCTXJKnVakycOBG//vqrKcIRERERERFZjMkGbnB3d8e///5rqnBEREREREQWYbIiKTExEbVq1TJVOCIiIiIi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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# vTotalCapST\n", + "y2020_TotCap_ST = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2020') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA'))].groupby('sST').sum().vSTTotCap\n", + "y2025_TotCap_ST = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2025') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA'))].groupby('sST').sum().vSTTotCap\n", + "y2030_TotCap_ST = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2030') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA'))].groupby('sST').sum().vSTTotCap\n", + "y2035_TotCap_ST = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2035') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA'))].groupby('sST').sum().vSTTotCap\n", + "y2040_TotCap_ST = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2040') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA'))].groupby('sST').sum().vSTTotCap\n", + "y2045_TotCap_ST = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2045') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA'))].groupby('sST').sum().vSTTotCap\n", + "y2050_TotCap_ST = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2050') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA'))].groupby('sST').sum().vSTTotCap\n", + "\n", + "\n", + "# Create a figure and a set of subplots\n", + "fig, ax = plt.subplots(1, 1, figsize=(10, 5))\n", + "\n", + "# Set the bar width\n", + "barWidth = 0.15\n", + "\n", + "# Set the position of the bars on the x-axis\n", + "r1 = np.arange(len(y2020_TotCap_ST))\n", + "r2 = [x + barWidth for x in r1]\n", + "r3 = [x + barWidth for x in r2]\n", + "r4 = [x + barWidth for x in r3]\n", + "r5 = [x + barWidth for x in r4]\n", + "r6 = [x + barWidth for x in r5]\n", + "r7 = [x + barWidth for x in r6]\n", + "r8 = [x + barWidth for x in r7]\n", + "r9 = [x + barWidth for x in r8]\n", + "\n", + "# Make the plot\n", + "plt.bar(r1, y2020_TotCap_ST, color='b', width=barWidth, label='2020')\n", + "plt.bar(r2, y2025_TotCap_ST, color='r', width=barWidth, label='2025')\n", + "plt.bar(r3, y2030_TotCap_ST, color='g', width=barWidth, label='2030')\n", + "plt.bar(r4, y2035_TotCap_ST, color='y', width=barWidth, label='2035')\n", + "plt.bar(r5, y2040_TotCap_ST, color='c', width=barWidth, label='2040')\n", + "plt.bar(r6, y2045_TotCap_ST, color='m', width=barWidth, label='2045')\n", + "plt.bar(r7, y2050_TotCap_ST, color='k', width=barWidth, label='2050')\n", + "\n", + "\n", + "# Add xticks on the middle of the group bars\n", + "plt.xlabel('Technologies', fontweight='bold')\n", + "plt.xticks([r + barWidth for r in range(len(y2020_TotCap_ST))], y2020_TotCap_ST.index, rotation=90)\n", + "plt.ylabel('ST UNITS')\n", + "plt.title('Total Capacity by Technology and Year')\n", + "# Create legend & Show graphic\n", + "plt.legend()\n", + "plt.grid()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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9wcALFy4EJ6enpgxYwYAoGrVqjh06BBmzZqFtm3byvb8eCaJiIiIiIiMEh8fDwBwdHQE8PIskUajQatWraRtvLy84OHhgaNHj+YZJzMGABw9elQnBgC0bds2zximwDNJREREr4mICN2BBb6+wkyZENGbJCMjAwEBAWjUqBGqV68OAIiJiYGlpSUcHBx0tnVxcUFMTEyOcY4cOYLff/8dO3bskNbFxMTAxcUlW4yEhAQkJSVJF481NRZJRERERERkMD8/P5w/fx6HDh0yOMb58+fRsWNHTJgwAW3atDFhdoZhdzsiIiIiIjKIv78/tm/fjvDwcJQrV05a7+rqitTUVMTFxelsHxsbC1dXV511Fy5cQMuWLTFw4ECMGzdOp83V1VVnRrzMGHZ2drKdRQJYJBERERERUT4JIeDv749NmzZh37598PT01GmvW7cuLCwssHfvXmnd5cuXcevWLfj4+EjroqKi0Lx5c3zxxRcICgrK9jg+Pj46MQBgz549OjHkwO52RERkVoosF+gQguNoiIgKOz8/P4SFhWHLli2wtbWVxhnZ29tDrVbD3t4e/fv3R2BgIBwdHWFnZ4ehQ4fCx8cH3t7eAF52sWvRogXatm2LwMBAKYZKpULp0qUBAIMGDcK8efMwcuRI9OvXD/v27cPatWt1xi3JgWeSiIiIiIgoXxYsWID4+Hj4+vrCzc1Nuv3+++/SNrNmzUKHDh3QpUsXNG3aFK6urti4caPUvn79ejx8+BArV67UiVGvXj1pG09PT+zYsQN79uxBrVq1MGPGDCxdulTW6b8BnkkiIiIiIiqU8jqxnpGRgYSEBNjZ2UGpLPjzHvqc9be2tkZwcDCCg4NzbJ84cSImTpz4yji+vr44depUflM0Cs8kERERERERaWGRREREREREpIVFEhERERERkRYWSURERERERFpYJBEREREREWlhkURERERERKSFRRIREREREZEWFklERERERERaWCQRERERERFpYZFERERERESkhUUSEREREVFhpFDkelOqVHAoWRJKlSrP7fS+5dPUqVNRr1492NrawtnZGZ06dcLly5d1tklOToafnx9KlSqFEiVKoEuXLoiNjZXaz5w5g549e8Ld3R1qtRpVq1bFnDlzdGJERERAoVBku8XExBi2T/XEIomIiIiIiPJl//798PPzQ2RkJPbs2QONRoM2bdogMTFR2mb48OHYtm0b1q1bh/379+PevXvo3Lmz1H7ixAk4Oztj5cqViIqKwrfffosxY8Zg3rx52R7v8uXLuH//vnRzdnaW9fkVkzU6ERERERG9dnbu3KmzHBoaCmdnZ5w4cQJNmzZFfHw8li1bhrCwMLRo0QIAEBISgqpVqyIyMhLe3t7o16+fToy33noLR48excaNG+Hv76/T5uzsDAcHB1mfkzaeSSIiIiIiIqPEx8cDABwdHQG8PEuk0WjQqlUraRsvLy94eHjg6NGjecbJjKGtdu3acHNzQ+vWrXH48GETZ58dzyQREREREZHBMjIyEBAQgEaNGqF69eoAgJiYGFhaWmY7++Pi4pLreKIjR47g999/x44dO6R1bm5uWLhwId577z2kpKRg6dKl8PX1xd9//413331XtufEIomIiIiIiAzm5+eH8+fP49ChQwbHOH/+PDp27IgJEyagTZs20voqVaqgSpUq0nLDhg1x7do1zJo1C7/99ptReeeF3e2IiIiIiMgg/v7+2L59O8LDw1GuXDlpvaurK1JTUxEXF6ezfWxsLFxdXXXWXbhwAS1btsTAgQMxbty4Vz5m/fr18e+//5ok/9ywSCIiIiIionwRQsDf3x+bNm3Cvn374OnpqdNet25dWFhYYO/evdK6y5cv49atW/Dx8ZHWRUVFoXnz5vjiiy8QFBSk12OfPn0abm5upnkiuWB3OyIiIiIiyhc/Pz+EhYVhy5YtsLW1lcYZ2dvbQ61Ww97eHv3790dgYCAcHR1hZ2eHoUOHwsfHB97e3gBedrFr0aIF2rZti8DAQCmGSqVC6dKlAQCzZ8+Gp6cnqlWrhuTkZCxduhT79u3D7t27ZX1+LJKIiIiIiChfFixYAADw9fXVWR8SEoI+ffoAAGbNmgWlUokuXbogJSUFbdu2xfz586Vt169fj4cPH2LlypVYuXKltL58+fK4efMmACA1NRVff/017t69CxsbG9SsWRN//fUXmjdvLuvzY5FERERERFQYCZFrU0ZGBhISEmBnZwelsuBH0Ig8cstkbW2N4OBgBAcH59g+ceJETJw4Mc8YI0eOxMiRIw1J0Sgck0RERERERKSFRRIREREREZEWFklERERERERazFokHThwAB9++CHKlCkDhUKBzZs367QLIfDdd9/Bzc0NarUarVq1wtWrV82TLBERERER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x2e9q8GxTYWvacHHljt+UcrdXustEh/P/WKO2OaWkJAAJyenVxZJBo9JWrVqFb777jskJSVh4sSJGDhwIIoVM+0QJzc3N7zzzjs666pWrYoNGzbkeh8rKytYWVllW29hYVGoX2S585MzPnM3T3zmXvCx5Y7/JuWuSPqv+3YSkrLFMjZ+frxO+12hePW+NDS2qfE1LfjYcscvCrknab1FtEO96fvFHLHNRd/nk++qZufOnRg9ejRu3LiBb775BoGBgShevHi+E9RHo0aNcPnyZZ11V65cQfny5WV5PCIiIiIiIr2LpGPHjmHUqFGIjIzEoEGD8Ndff8HJyUnO3DB8+HA0bNgQU6ZMQffu3XHs2DEsXrwYixcvlvVxiYiIiIjozaV3keTt7Q21Wo1BgwbB09MTYWFhOW73v//9z2TJ1atXD5s2bcKYMWMwefJkeHp6Yvbs2fj0009N9hhERERERETa9C6SPDw8oFAosHnz5ly3USgUJi2SAKBDhw7o0KGDSWMSERERERHlRu8i6ebNmzKmQUREREREVDgozZ0AERERERFRYaL3maTAwMAc19vb2+Ptt99G586dc5x6m4iIiIiIqCjRu0g6depUjuvj4uLw77//Yvz48di3bx88PDxMlhwREREREVFB07tICg8Pz7UtISEBn376KUaPHp3rrHdERERERERFgUnGJNnZ2WH8+PE4fPiwKcIRERERERGZjckmbnBycsKTJ09MFY6IiIiIiMgsTFYkRUZGomLFiqYKR0REROZgb6/7fyKiN5DeY5LOnj2b4/r4+HicOHECU6ZMwYQJE0yWGBERERERkTnoXSTVrl0bCoUCQohsbU5OTggMDMSQIUNMmhwREREREVFB07tIunHjRo7r7ezsULJkSZMlREREREREZE56F0nly5eXMw8iIiIiIqJCwWQTNxAREREREb0OWCQRERERERFpYZFERERERESkRe8i6cCBA0hLS5MzFyIiIiIiIrPTu0hq3rw5njx5ImcuREREREREZqd3kZTT9ZGIiIiIiIheN3pPAQ4ACoVCrjyIiIiIZBMR8d93GF9f/vBLRHnLV5HUp08fWFlZ5bnNxo0bjUqIiIiIiIjInPJVJNna2kKtVsuVCxERERERkdnlq0iaO3cunJ2d5cqFiIiIiIjI7PSeuIHjkYiIiIiI6E3A2e2IiIiIiIi06F0khYeHw9HRUc5ciIiIiIiIzE7vIsnS0hI7d+7UWbdixQp4enrC2dkZAwcOREpKiskTJCIiIiIiKkh6F0mTJ09GVFSUtHzu3Dn0798frVq1wujRo7Ft2zZMnTpVliSJiKjwU0xSSDciIqKiTO/Z7U6fPo3vv/9eWl6zZg0aNGiAJUuWAADc3d0xYcIETJw40eRJEhFR0aaIiNBZDjdPGpSDrPMypfJKH0RE+p9Jevr0KVxcXKTl/fv3o127dtJyvXr1cPv2bdNmR0REREREVMD0LpJcXFxw48YNAEBqaipOnjwJb29vqf3Zs2ewsLAwfYZEREREREQFSO8i6YMPPsDo0aNx8OBBjBkzBjY2NmjSpInUfvbsWVSsWFGWJImIiIiIiAqK3mOSvv/+e3Tu3BnNmjVDiRIl8Ouvv8LS0lJqX758Odq0aSNLkkRERERERAVF7yLJyckJBw4cQHx8PEqUKAGVSqXTvm7dOpQoUcLkCRIRERERERUkvYukTPb29jmu54VmiYiIiIjodaD3mCQiIiIiIqI3AYskIiIiIiIiLSySiIiIiIiItLBIIiIiIiIi0sIiiYiIiIiISAuLJCIiIiIiIi0skoiIiIiIiLSwSCIiIiIiItLCIomIiIiIiEgLiyQiIiIiIiItLJKIiIiIiIi0sEgiIiIiIiLSwiKJiIiIiIhIC4skIiIiIiIiLSySiIiIiIiItLBIIiIiIiIi0sIiiYiIiIiISAuLJCIiIiIiIi0skoiIiIiIiLSwSCIiIiIiItLCIomIiIiIiEhLkSqSfvzxRygUCgQEBJg7FSIiIiIiek0VmSLp+PHjWLRoEWrWrGnuVIiIiIiI6DVWJIqk58+f49NPP8WSJUtQsmRJc6dDRERERESvsWLmTkAffn5+aN++PVq1aoUffvghz21TUlKQkpIiLSckJAAANBoNNBqNrHkaIjMnuXKTMz5zN0985l7wseWO/7rkrlaqs63PpBZCZ1motdqg1mnTvi/3e/5iC5H7vsyNWvcu0Pz/Co1aDRSx/Z5XbO19Y+hj83gs+Nimjq99vGs03C/miG1u+j4nhRBZ/nIVMmvWrEFQUBCOHz8Oa2tr+Pr6onbt2pg9e3aO20+cOBGTJk3Ktj4sLAw2NjYyZ0tERERERIXVixcv0KtXL8THx8POzi7X7Qp1kXT79m2899572LNnjzQW6VVFUk5nktzd3fHo0aM8d4S5aDQa7NmzB61bt4aFhUWRis/czROfuRd8bLnjvy65O81wktbHj47X2c7+0CGd5R3t//t3e7TXaYuP/+++3O/5i33okL3Odo0bx2e9azb2unfBI7Ur9ixfjtb9+sEiJsYk+Woz12uqvW/02S/5jW+s1/F4LIzxtY/3+HjuF3PENreEhAQ4OTm9skgq1N3tTpw4gQcPHuDdd9+V1qWnp+PAgQOYN28eUlJSoFKpdO5jZWUFKyurbLEsLCwK9Yssd35yxmfu5onP3As+ttzxi3ruSRlJOsvakhQKnWVFklYbknTacsqR+12/2ArFq/dlVkm6d4HF/78eFklJr81+AXT3jbGPy+Ox4GObKr728a4d6k3fL+aIbS76Pp9CXSS1bNkS586d01nXt29feHl5YdSoUdkKJCIiIiIiImMV6iLJ1tYW1atX11lXvHhxlCpVKtt6IiIiIiIiUygSU4ATEREREREVlEJ9JiknERER5k6BiIiIiIheYzyTREREREREpIVFEhERERERkRYWSURERERERFpYJBEREREREWlhkURERERERKSFRRIREREREZEWFklERERERERaitx1koiIiIjkplDoLgthnjyIyDx4JomIiIiIiEgLiyQiIiIiIiItLJKIiIiIiIi0sEgiIiIiIiLSwiKJiIiIiIhIC4skIiIiIiIiLSySiIiIiIiItLBIIiIiIiIi0sIiiYiIiIiISAuLJCIiIiIiIi0skoiIiIiIiLSwSCIiIiIiItLCIomIiIiIiEgLiyQiIiIiIiItLJKIiIiIiIi0FDN3AkREREQFSRERobMsfH3NkgcRFV4skoiIiIiItEREKHSWfX2FmTIhc2F3OyIiIiIiIi0skoiIiIiIiLSwSCIiIiIiItLCIomIiIiIiEgLiyQiIiIiIiItLJKIiIiIiIi0sEgiIiIiIiLSwiKJiIiIiIhIC4skIiIiIiIiLSySiIiIiIiItLBIIiIiIiIi0sIiiYiIiIiISEsxcydARERE8lBEREj/Fr6+ZsuDCg/7H+2RlJEkLYsJwozZEBVePJNERERERESkhUUSERERERGRFhZJRERERK+iUAD29i//nfl/emMoIiKkG70ZWCQRERERERFpYZFERESG4S/rRET0muLsdkRERERvqIgIhfRvX1/OdEeUiWeSiIiIiIiItLBIIiIiIiIi0sIiiYiIiIiISAuLJCIiIiIiIi0skoiIiIiIiLSwSCIiIiIiItLCIomIiIiIiEgLiyQiIiIiIiItvJgsERG98RST/rugppjAC2pm0t4vAPcNEb05eCaJiIjeCArFfzcoFIC9/cuGzP8TERH9P55JIiKiQs/+R3skZSRJyzyjQUSmpn3mNLyZGROhQqFQn0maOnUq6tWrB1tbWzg7O6NTp064fPmyudMiIiIZ5Xi2h4iIqAAV6iJp//798PPzQ2RkJPbs2QONRoM2bdogMTHR3KkREREREdFrqlB3t9u5c6fOcmhoKJydnXHixAk0bdrUTFkRERERFSEKBaBWA6tXmzsToiKjUJ9Jyio+Ph4A4OjoaOZMiIiIiIjodVWozyRpy8jIQEBAABo1aoTq1avnul1KSgpSUlKk5YSEBACARqOBRqORPc/8ysxJrtzkjM/czROfuRd8bLnjF9nc1Wpo1OqXsdVqqLV+dsv6WGqhO9GCUGu1QQ1d/58v/ouvVupuY8hzUWuF0I79qtwNZY5jRgjd/aSGyHafrNRZdn9u+yWvGPlhrveS9r7R3i+5bZ9tv2Q5ZmDi/GX9HFDn/l7Sfmsa+thF6TNM53NAoxtbe99k+cjS672UVVHaLwUZ29z0fU4KIbIeBoXT4MGD8eeff+LQoUMoV65crttNnDgRkyZNyrY+LCwMNjY2cqZIRERERESF2IsXL9CrVy/Ex8fDzs4u1+2KRJHk7++PLVu24MCBA/D09Mxz25zOJLm7u+PRo0d57ghz0Wg02LNnD1q3bg0LC4siFZ+5myc+cy/42HLHL7K529tDo1Zjz/LlaN2vH5wC/puiO350vO6mhw7pLO9o/9+/26M9dMX//3//i9/vfD+dKcCzxtczXa1H0D93Q5njmDl0SHc2wPbYIf07vnHjHGNlnUDwkdo1x/0CmGbfmOu9pL1vtPcLkPO+ybpfsh4zFjExpkscMn8O2Of+Xtqh9dQbNzbs9S1Kn2E6nwPxurGdZjhJbTuyHBL6vJfkzLug48uduzklJCTAycnplUVSoe5uJ4TA0KFDsWnTJkRERLyyQAIAKysrWFlZZVtvYWFRqF9kufOTMz5zN0985l7wseWOX+RyT/rvi5ZFUpLOF6+sj5OkUOgsK7S+eydB94s4YPH///1vfVJG3vHzma5O7FflbqyCPGYUCt19mQSFzrY5Scqy+zP3Tdb9klcMQxT0e0l732jvl8zts8ptvwAv902R+hxIyv29pP3WNPZxi8JnmM7ngIX2vy1y3S+A7jFz2PKwTltzNJf+ndO5h6KwX8wR21z0fT6Fukjy8/NDWFgYtmzZAltbW8T8/6829vb2UGftLExERERERGQChXp2uwULFiA+Ph6+vr5wc3OTbr///ru5UyMiIiIiotdUoT6TVASGSxERERER0WumUBdJRESvo6x93VPV9i8v8mhvD8Uo3YEQ4c3++3dzhOu2Nddua67Txh+ZKKsIRYTOsq/wNUseRERFQaHubkdERERERFTQWCQRERFRwVAo/puDOesc20REhQi72xEREdEbTbsrIrshEhHAM0lEREREREQ6WCQRERERERFpYZFERERERESkhUUSERERERGRFhZJREREREREWlgkERERERERaWGRREREREREpIVFEhERERERkRYWSURERERERFqKmTsBIiIiIjI/RUSEzrLw9TVLHkSFAc8kERERERERaWGRREREREREpIVFEhERERERkRYWSURERERERFpYJBEREREREWlhkURERERERKSFRRIREREREZEWXieJiIiIiApUhCJCZ7k5mkv/FkIUcDZE2fFMEhERERERkRaeSSIieg0pFC//zx9kieh1FRGhkP7dHOE6bcLXt4CzodcNiyQiIiIieq1od+fzFb5my4OKLna3IyIiIiIi0sIzSUREREQkO0VEhPTv8Nw3IyoUWCQREREVYYpJ/43LCG9mxkQKGe39AnDfEFH+sLsdERERERGRFp5JIiIiIqLXlkKhyLKG037Sq/FMEhERERERkRaeSSIiIiLKJ+0xT2ICz0wQvW54JomIiIiIiEgLzyQRERERUaFn/6M9kjKSpGXOWEhy4pkkIiIiIiqcFArA3t7cWdAbiEUSERERERGRFhZJREREREREWlgkERERERERaWGRREREREREpIVFEhERERERkRYWSURERERERFp4nSQiIiIiMrmICEWWNeFmyYPIECySyHD29sDq1YC9PRSjknSatC/w1jzLh2J48//+7St8ZUxQXgqF7oe/EMJMmRAREVG+KRSAWi19l8EocydEhQm72xERERUl2hfX5EU2dXG/EJGJsEgiIiIiIiLSwu52REQ50O5NKaDbJUO7e6l211JAt3up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SgolJyeTm5sbHT161HI+Tp8+LTv+77//XqiHUjj23phMJssjrxQ+pec9L9RKiStRogRVrFiRJk6cSGfOnLH6fqvxXTdqSlx+19LBwYGqVatGS5YskRU3L86ePUsTJkygcuXKkclkol69etHWrVtlp5q++uqrFBkZme/xiIgIevXVV+U2lzIzM6lr165kMpnIz8+POnfuTJ06daLq1auT2WymLl26yN5rxp2aVa5cOdqyZYvl+enTp8nOzo4ePXqkOHZO1L6mRE/7rujoaGrevDk5OztTly5d6McffyQHBwfF58bLy4t27dpleX716lUym82qpyRmk5mZSZs2baL33nuPHB0dFe0z406Jy0lWVhZt2bKFunXrRkWKFKGyZcvSsGHDZMfLeU/NfuS+r8rtf7nvSyaTia5fv2557urqSmfPnpUdT/BiI9ztNCSvYq8ALK8RQzFZNeNzOcRx14/iLuKrNWq553Gf95zkTon74IMPMG3aNNmOSDndvvKa8VZ6TbV0iVOT/K5pcnIyDh06hPnz52Pu3LmyV8HyIisrC7GxsYiIiMDGjRvh6uoqy6ls7ty5mDZtGlauXJnnSk/fvn0xfvx4K+t0Ofzwww+IiYmxWIxXq1YNPXv2VFS369GjR5bVmH379llWY3r06IEjR44onrm3s7PDlStX4O3tbXmtaNGiOHHiBHx8fBTFzgu1rmlusldkli9fjitXriAoKEjRiozZbMa1a9es6pW5urri2LFj7AUwb926hRUrVsj+PsbExCAyMhJ79+61SolzcnJS3T0vJ7dv38bKlSsRFRWFo0ePyoqR+54KWN9XlfS/WowHtm/fbrlvvvnmm1i9ejXKlStn9b46derIim9UuFMFjYoQSRpi5GKyWth0c8F5XrLrNeRM37t+/Tr+85//4MGDB/jXv/5lydtWitpCg5u8UuL+/e9/q5ISx/1bmjlzJr7++mt89NFH2L59O27evInjx49bjs+bNw+//PILfvvtN8mxuVPiCiIyMhILFixgu9EpGThmZWWhR48eWLduHapXr44aNWqAiHDy5EmcOXMGnTp1wpo1a2QX2tUKtYUAwF+ksiCUioG8UEuE2dnZ4fTp01bnpVy5cti9e7eVeJSTmnX37l1ER0ejb9++z/x9SkoKVqxYkecxqWSnxGX363fu3MEPP/ygeH9MNnFxcVY1x9Sw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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# vTotalCapST\n", + "y2020_TotCap_ST = data_results['vSTNewCap'][(data_results['vSTNewCap'].sYear=='y2020') & (data_results['vSTNewCap'].sST.str.startswith('sST_DSTRA'))].groupby('sST').sum().vSTNewCap\n", + "y2025_TotCap_ST = data_results['vSTNewCap'][(data_results['vSTNewCap'].sYear=='y2025') & (data_results['vSTNewCap'].sST.str.startswith('sST_DSTRA'))].groupby('sST').sum().vSTNewCap\n", + "y2030_TotCap_ST = data_results['vSTNewCap'][(data_results['vSTNewCap'].sYear=='y2030') & (data_results['vSTNewCap'].sST.str.startswith('sST_DSTRA'))].groupby('sST').sum().vSTNewCap\n", + "y2035_TotCap_ST = data_results['vSTNewCap'][(data_results['vSTNewCap'].sYear=='y2035') & (data_results['vSTNewCap'].sST.str.startswith('sST_DSTRA'))].groupby('sST').sum().vSTNewCap\n", + "y2040_TotCap_ST = data_results['vSTNewCap'][(data_results['vSTNewCap'].sYear=='y2040') & (data_results['vSTNewCap'].sST.str.startswith('sST_DSTRA'))].groupby('sST').sum().vSTNewCap\n", + "y2045_TotCap_ST = data_results['vSTNewCap'][(data_results['vSTNewCap'].sYear=='y2045') & (data_results['vSTNewCap'].sST.str.startswith('sST_DSTRA'))].groupby('sST').sum().vSTNewCap\n", + "y2050_TotCap_ST = data_results['vSTNewCap'][(data_results['vSTNewCap'].sYear=='y2050') & (data_results['vSTNewCap'].sST.str.startswith('sST_DSTRA'))].groupby('sST').sum().vSTNewCap\n", + "\n", + "\n", + "# Create a figure and a set of subplots\n", + "fig, ax = plt.subplots(1, 1, figsize=(10, 5))\n", + "\n", + "# Set the bar width\n", + "barWidth = 0.15\n", + "\n", + "# Set the position of the bars on the x-axis\n", + "r1 = np.arange(len(y2020_TotCap_ST))\n", + "r2 = [x + barWidth for x in r1]\n", + "r3 = [x + barWidth for x in r2]\n", + "r4 = [x + barWidth for x in r3]\n", + "r5 = [x + barWidth for x in r4]\n", + "r6 = [x + barWidth for x in r5]\n", + "r7 = [x + barWidth for x in r6]\n", + "r8 = [x + barWidth for x in r7]\n", + "r9 = [x + barWidth for x in r8]\n", + "\n", + "# Make the plot\n", + "plt.bar(r1, y2020_TotCap_ST, color='b', width=barWidth, label='2020')\n", + "plt.bar(r2, y2025_TotCap_ST, color='r', width=barWidth, label='2025')\n", + "plt.bar(r3, y2030_TotCap_ST, color='g', width=barWidth, label='2030')\n", + "plt.bar(r4, y2035_TotCap_ST, color='y', width=barWidth, label='2035')\n", + "plt.bar(r5, y2040_TotCap_ST, color='c', width=barWidth, label='2040')\n", + "plt.bar(r6, y2045_TotCap_ST, color='m', width=barWidth, label='2045')\n", + "plt.bar(r7, y2050_TotCap_ST, color='k', width=barWidth, label='2050')\n", + "\n", + "\n", + "# Add xticks on the middle of the group bars\n", + "plt.xlabel('Technologies', fontweight='bold')\n", + "plt.xticks([r + barWidth for r in range(len(y2020_TotCap_ST))], y2020_TotCap_ST.index, rotation=90)\n", + "plt.ylabel('ST UNITS')\n", + "plt.title('New Capacity ST Tra Year')\n", + "# Create legend & Show graphic\n", + "plt.legend()\n", + "plt.grid()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sSTsYearvSTTotCapvSTNewCapvSTDecCapvInvCostSTvEmiCO2STvEmiSOxSTvEmiPM25ST
154sST_DSOTH_RES_HPCOP6y202026.5091007.000005.79690015.6558500.00.00.0
155sST_DSOTH_RES_HPCOP6y202534.91557016.000007.59353017.7846140.00.00.0
156sST_DSOTH_RES_HPCOP6y203050.33434325.000009.58122713.1579900.00.00.0
157sST_DSOTH_RES_HPCOP6y203593.14498356.2500013.43936018.9740720.00.00.0
158sST_DSOTH_RES_HPCOP6y2040159.20480087.5000021.44018319.1943140.00.00.0
159sST_DSOTH_RES_HPCOP6y2045240.932200118.7500037.02260017.0406280.00.00.0
160sST_DSOTH_RES_HPCOP6y2050325.685385146.3210161.56782513.7909090.00.00.0
\n", + "
" + ], + "text/plain": [ + " sST sYear vSTTotCap vSTNewCap vSTDecCap \\\n", + "154 sST_DSOTH_RES_HPCOP6 y2020 26.509100 7.00000 5.796900 \n", + "155 sST_DSOTH_RES_HPCOP6 y2025 34.915570 16.00000 7.593530 \n", + "156 sST_DSOTH_RES_HPCOP6 y2030 50.334343 25.00000 9.581227 \n", + "157 sST_DSOTH_RES_HPCOP6 y2035 93.144983 56.25000 13.439360 \n", + "158 sST_DSOTH_RES_HPCOP6 y2040 159.204800 87.50000 21.440183 \n", + "159 sST_DSOTH_RES_HPCOP6 y2045 240.932200 118.75000 37.022600 \n", + "160 sST_DSOTH_RES_HPCOP6 y2050 325.685385 146.32101 61.567825 \n", + "\n", + " vInvCostST vEmiCO2ST vEmiSOxST vEmiPM25ST \n", + "154 15.655850 0.0 0.0 0.0 \n", + "155 17.784614 0.0 0.0 0.0 \n", + "156 13.157990 0.0 0.0 0.0 \n", + "157 18.974072 0.0 0.0 0.0 \n", + "158 19.194314 0.0 0.0 0.0 \n", + "159 17.040628 0.0 0.0 0.0 \n", + "160 13.790909 0.0 0.0 0.0 " + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Lets define a dataset with the characteristics of each CE technology\n", + "# The dataset NAMED CE TECHNOLOGIES will contain the following columns:\n", + "# - sTE: Name of the technology\n", + "# - sYear: Year of the data\n", + "# - vInvCostST: Investment cost of the technology\n", + "# - vSTNewCap: New capacity of the technology\n", + "# - vSTTotCap: Total capacity of the technology\n", + "# - vSTDecCap: Decomissioned capacity of the technology\n", + "# - vEmiCO2ST: CO2 emissions of the technology\n", + "# - vEmiSOxST: SOx emissions of the technology\n", + "# - vEmiPM25ST: PM2.5 emissions of the technology\n", + "\n", + "# # Create the dataset\n", + "# import pandas as pd\n", + "ST_TECHNOLOGIES = pd.DataFrame(columns=['sST', 'sYear', 'vSTTotCap', 'vSTNewCap', 'vSTDecCap', 'vInvCostST' , 'vEmiCO2ST', 'vEmiSOxST', 'vEmiPM25ST'])\n", + "\n", + "# # Fill the dataset with the data\n", + "#ST_TECHNOLOGIES_sST = pd.DataFrame(data_results['vSTTotCap'][data_results['vSTTotCap'].sST.str.startswith('sST_DSOTH_RES')].groupby('sST').sum().vSTTotCap).index\n", + "#ST_TECHNOLOGIES['sYear'] = data_results['vInvCostST'].sYear\n", + "ST_TECHNOLOGIES_vSTTotCap = pd.DataFrame(data_results['vSTTotCap'][data_results['vSTTotCap'].sST.str.startswith('sST_DSOTH_RES')].groupby(['sST','sYear']).sum().vSTTotCap).reset_index()\n", + "ST_TECHNOLOGIES_vSTNewCap = pd.DataFrame(data_results['vSTNewCap'][data_results['vSTNewCap'].sST.str.startswith('sST_DSOTH_RES')].groupby(['sST','sYear']).sum().vSTNewCap).reset_index()\n", + "ST_TECHNOLOGIES_vSTDecCap = pd.DataFrame(data_results['vSTDecCap'][data_results['vSTDecCap'].sST.str.startswith('sST_DSOTH_RES')].groupby(['sST','sYear']).sum().vSTDecCap).reset_index()\n", + "ST_TECHNOLOGIES_vInvCostST = pd.DataFrame(data_results['vInvCostST'][data_results['vInvCostST'].sST.str.startswith('sST_DSOTH_RES')].groupby(['sST','sYear']).sum().vInvCostST).reset_index()\n", + "ST_TECHNOLOGIES_vEmiCO2ST = pd.DataFrame(data_results['vEmiCO2ST'][data_results['vEmiCO2ST'].sST.str.startswith('sST_DSOTH_RES')].groupby(['sST','sYear']).sum().vEmiCO2ST).reset_index()\n", + "ST_TECHNOLOGIES_vEmiSOxST = pd.DataFrame(data_results['vEmiSOxST'][data_results['vEmiSOxST'].sST.str.startswith('sST_DSOTH_RES')].groupby(['sST','sYear']).sum().vEmiSOxST).reset_index()\n", + "ST_TECHNOLOGIES_vEmiPM25ST = pd.DataFrame(data_results['vEmiPM25ST'][data_results['vEmiPM25ST'].sST.str.startswith('sST_DSOTH_RES')].groupby(['sST','sYear']).sum().vEmiPM25ST).reset_index()\n", + "\n", + "# Join the dataframes to create a single dataframe preserving the columns sST and sYear as keys\n", + "ST_TECHNOLOGIES = pd.merge(ST_TECHNOLOGIES_vSTTotCap, ST_TECHNOLOGIES_vSTNewCap, on=['sST','sYear'])\n", + "ST_TECHNOLOGIES = pd.merge(ST_TECHNOLOGIES, ST_TECHNOLOGIES_vSTDecCap, on=['sST','sYear'])\n", + "ST_TECHNOLOGIES = pd.merge(ST_TECHNOLOGIES, ST_TECHNOLOGIES_vInvCostST, on=['sST','sYear'])\n", + "ST_TECHNOLOGIES = pd.merge(ST_TECHNOLOGIES, ST_TECHNOLOGIES_vEmiCO2ST, on=['sST','sYear'])\n", + "ST_TECHNOLOGIES = pd.merge(ST_TECHNOLOGIES, ST_TECHNOLOGIES_vEmiSOxST, on=['sST','sYear'])\n", + "ST_TECHNOLOGIES = pd.merge(ST_TECHNOLOGIES, ST_TECHNOLOGIES_vEmiPM25ST, on=['sST','sYear'])\n", + "\n", + "ST_TECHNOLOGIES[ST_TECHNOLOGIES['sST']=='sST_DSOTH_RES_HPCOP6']" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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a9eGjY0N3nvvPZw/fx779u1Dfn6+dP9S7dq1oaOjg6ioKJw5cwZubm6oVasWoqKiMHPmTHzwwQdSwTR8+HAEBQVh3LhxmD9/PmJjY7Fq1SqsXLlS2u706dPRvXt3rFixAv369cPOnTtx7tw5adgFhUKBGTNm4JNPPkGjRo3g5OSExYsXw9bWFp6enpWXMCIiIlJbVVpUnTt3Dm5ubtJ00f1R3t7eCAwMxM8//wwAaN26tcpyx44dQ48ePaCrq4udO3ciMDAQ2dnZcHJywsyZM1XuszIxMcHhw4fh6+uLdu3awdzcHP7+/tJwCgDQuXNnhIWFYdGiRfjoo4/QqFEj7N27F82bN5di5s2bh8zMTPj4+CA1NRVdunTBwYMHoaenVxGpISIiompGIYQQVd2J10V6ejpMTEyQlpYm+6VARZBC1vWpAxFQvkOTuSjEPBRiHv6hqHmpQHl+wZiHQsxD6ZX291ut76kiIiIiqi5YVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQyqxWtqiIjKLbAGPuAcUNUdIKKS8EwVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgIN/EtVUHPSSiKhS8UwVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgDeqU83DG7SJiKgK8EwVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJoEqLqhMnTmDAgAGwtbWFQqHA3r17VdqFEPD394eNjQ309fXh7u6O69evq8Q8fPgQI0aMgLGxMUxNTTFu3DhkZGSoxFy8eBFdu3aFnp4e7OzsEBwcXKwvu3fvRuPGjaGnp4cWLVrgwIEDZe4LERERvb6qtKjKzMxEq1atsG7duhLbg4ODsXr1amzcuBFnzpyBoaEhPDw8kJWVJcWMGDECly9fRnh4OPbt24cTJ07Ax8dHak9PT0fv3r3h4OCA6OhoLF++HIGBgfj666+lmFOnTsHLywvjxo3DhQsX4Onp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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "y2020_sTEELE_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEELE')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2025_sTEELE_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEELE')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2030_sTEELE_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEELE')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2035_sTEELE_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEELE')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2040_sTEELE_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEELE')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2045_sTEELE_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEELE')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2050_sTEELE_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEELE')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEOPDIE_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2025_sTEOPDIE_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2030_sTEOPDIE_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2035_sTEOPDIE_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2040_sTEOPDIE_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2045_sTEOPDIE_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2050_sTEOPDIE_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTENAGAS_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2025_sTENAGAS_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2030_sTENAGAS_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2035_sTENAGAS_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2040_sTENAGAS_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2045_sTENAGAS_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2050_sTENAGAS_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEOLPG_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOLPG')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2025_sTEOLPG_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOLPG')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2030_sTEOLPG_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOLPG')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2035_sTEOLPG_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOLPG')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2040_sTEOLPG_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOLPG')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2045_sTEOLPG_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOLPG')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2050_sTEOLPG_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOLPG')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEBIOMA_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIOMA')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2025_sTEBIOMA_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIOMA')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2030_sTEBIOMA_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIOMA')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2035_sTEBIOMA_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIOMA')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2040_sTEBIOMA_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIOMA')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2045_sTEBIOMA_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIOMA')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2050_sTEBIOMA_RES = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIOMA')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "\n", + "# Graph bar stackplot\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "sTEELE_RES = [y2020_sTEELE_RES, y2025_sTEELE_RES, y2030_sTEELE_RES, y2035_sTEELE_RES, y2040_sTEELE_RES, y2045_sTEELE_RES, y2050_sTEELE_RES]\n", + "sTEOPDIE_RES = [y2020_sTEOPDIE_RES, y2025_sTEOPDIE_RES, y2030_sTEOPDIE_RES, y2035_sTEOPDIE_RES, y2040_sTEOPDIE_RES, y2045_sTEOPDIE_RES, y2050_sTEOPDIE_RES]\n", + "sTENAGAS_RES = [y2020_sTENAGAS_RES, y2025_sTENAGAS_RES, y2030_sTENAGAS_RES, y2035_sTENAGAS_RES, y2040_sTENAGAS_RES, y2045_sTENAGAS_RES, y2050_sTENAGAS_RES]\n", + "sTEOLPG_RES = [y2020_sTEOLPG_RES, y2025_sTEOLPG_RES, y2030_sTEOLPG_RES, y2035_sTEOLPG_RES, y2040_sTEOLPG_RES, y2045_sTEOLPG_RES, y2050_sTEOLPG_RES]\n", + "sTEBIOMA_RES = [y2020_sTEBIOMA_RES, y2025_sTEBIOMA_RES, y2030_sTEBIOMA_RES, y2035_sTEBIOMA_RES, y2040_sTEBIOMA_RES, y2045_sTEBIOMA_RES, y2050_sTEBIOMA_RES]\n", + "\n", + "plt.bar(years, sTEELE_RES, label='Electricity', color='blue')\n", + "plt.bar(years, sTEOPDIE_RES, label='Diesel', color='red', bottom=sTEELE_RES)\n", + "plt.bar(years, sTENAGAS_RES, label='Natural Gas', color='green', bottom=[sum(x) for x in zip(sTEELE_RES, sTEOPDIE_RES)])\n", + "plt.bar(years, sTEOLPG_RES, label='LPG', color='orange', bottom=[sum(x) for x in zip(sTEELE_RES, sTEOPDIE_RES, sTENAGAS_RES)])\n", + "plt.bar(years, sTEBIOMA_RES, label='Biomass', color='brown', bottom=[sum(x) for x in zip(sTEELE_RES, sTEOPDIE_RES, sTENAGAS_RES, sTEOLPG_RES)])\n", + "plt.title('TE consumed by ST in RES sector')\n", + "plt.xlabel('Year')\n", + "plt.ylabel('[GWh]')\n", + "plt.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_28048\\3538486197.py:50: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2025gasCE_TEELECE = data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2025')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2025')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2025')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2025')].vQCESecOUT.sum()\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_28048\\3538486197.py:51: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2030gasCE_TEELECE = data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2030')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2030')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2030')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2030')].vQCESecOUT.sum()\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_28048\\3538486197.py:52: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2035gasCE_TEELECE = data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2035')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2035')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2035')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2035')].vQCESecOUT.sum()\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_28048\\3538486197.py:53: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2040gasCE_TEELECE = data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2040')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2040')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2040')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2040')].vQCESecOUT.sum()\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_28048\\3538486197.py:54: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2045gasCE_TEELECE = data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2045')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2045')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2045')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2045')].vQCESecOUT.sum()\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_28048\\3538486197.py:55: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2050gasCE_TEELECE = data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2050')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2050')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2050')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2050')].vQCESecOUT.sum()\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA9sAAAHWCAYAAABniJorAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAAB6LElEQVR4nO3deVxV1f7/8fcBGRQEnBBNVFALcQjn0BRxwrTSsptThUN2nTIlrWwQh8q0zCmHBqdMr+a1LPOqOWGmluZQmkOmGJqCIyAqgrB/f/jl/DyBeg5uBPT1fDzO4+FZe+21P3uvNvFh7b2WxTAMQwAAAAAAwDRO+R0AAAAAAAB3G5JtAAAAAABMRrINAAAAAIDJSLYBAAAAADAZyTYAAAAAACYj2QYAAAAAwGQk2wAAAAAAmIxkGwAAAAAAk5FsAwAAAABgMpJtALCDxWLRyJEj8zsMGz169FDlypUd3q9y5crq0aOH6fHgxmJiYmSxWBQTE5Pfodht7ty5slgsOnr0qGltzp8/X0FBQXJxcZGPj49p7QIAUBCRbAO4Z2UlEzf6/PTTT3ckjkuXLmnkyJH5lojt27dPI0eONDWput6mTZv09NNP67777pOrq6u8vb3VqFEjjR49WgkJCXlyzPwyffp0zZ07N7/DsNG8eXNZLBZVq1Ytx+1r1qyx/jf/3//+N8/iOHDggHr06KEqVaro008/1SeffJInxzl69OhN7+vrP0ePHrX+IeRGn0WLFlnbrly58g3rtW3b1lpv5MiRslgsOnPmzA3jdOS4kpSRkaE5c+aoefPmKlmypNzc3FS5cmX17NlTv/zyi7VeQfm5BgCQiuR3AACQ30aPHq2AgIBs5VWrVr0jx7906ZJGjRol6VpiZK9PP/1UmZmZDh/v4MGDcnL6/39r3bdvn0aNGqXmzZvnaqT8ZkaMGKExY8YoMDBQPXr0UGBgoFJTU7Vjxw5NmDBB8+bN0+HDh009Zn6aPn26Spcune3JgWbNmuny5ctydXXNl7jc3d31559/atu2bWrYsKHNtgULFsjd3V2pqak25c8++6y6dOkiNzc3U2KIiYlRZmamJk+enKf3VpkyZTR//nybsgkTJuj48eOaOHFitrpZf2QaNGiQGjRokK290NBQm+8hISF6+eWXs9UrX758ruK157iXL1/Wk08+qVWrVqlZs2Z6/fXXVbJkSR09elRffvml5s2bp7i4OFWoUMG6T37/XAMAkGwDgB555BHVr18/v8Ow28WLF+Xh4SEXF5dc7W9W8nQrixcv1pgxY/T0009r/vz52RLNiRMnZkt+ChLDMJSamqqiRYvedltOTk5yd3c3IarcqVKliq5evar//Oc/Nsl2amqqvv76a7Vv315Lly612cfZ2VnOzs6mxXDq1ClJMvXx8UuXLqlYsWI2ZR4eHnrmmWdsyhYtWqTz589nK79e06ZN9dRTT93ymPfdd99N23GUPccdNmyYVq1apYkTJ2rw4ME226Kjo3O8jwrbzzUAuBvxGDkA5NLff/+tXr16qWzZsnJzc1ONGjU0e/bsbPVSU1M1cuRI3X///XJ3d1e5cuX05JNP6vDhwzp69KjKlCkjSRo1apT1Uc+s98N79OghT09PHT58WO3atVPx4sXVvXt367Z/jkRnjRzWqlVL7u7uKlOmjNq2bWvzmOn172zPnTtX//rXvyRJ4eHh1uPHxMQoMjJSpUuXVnp6erZzatOmjR544IGbXp8RI0aodOnSmjVrVo4jut7e3jm+B79y5Uo1bdpUHh4eKl68uNq3b6/ff//dpk7Wdfn777/VsWNHeXp6qkyZMho6dKgyMjKyXZNJkyapRo0acnd3V9myZfXvf/9b58+ft6lXuXJlPfroo1q9erXq16+vokWL6uOPP5YkzZkzRy1atJCvr6/c3NwUHBysGTNmZNv/999/18aNG63XMetJhRu9s71kyRLVq1dPRYsWVenSpfXMM8/o77//zvW53kzXrl21ePFim6chli9frkuXLunpp5/OVv+f72yvX79eTk5OGjFihE29hQsXymKxZLse/7w20dHRkq6NJv9zDoTp06erRo0acnNzU/ny5TVgwAAlJibatNG8eXPVrFlTO3bsULNmzVSsWDG9/vrrdp9/YXX8+HF9/PHHat26dbZEW7r2R5GhQ4fajGoDAAoGkm0A97ykpCSdOXPG5nP27Nmb7pOQkKCHHnpIa9eu1cCBA62Pxvbu3VuTJk2y1svIyNCjjz6qUaNGqV69epowYYJeeuklJSUlae/evSpTpow1SXniiSc0f/58zZ8/X08++aS1jatXryoiIkK+vr764IMP1KlTpxvG1bt3bw0ePFj+/v4aN26cXnvtNbm7u9/wPc1mzZpp0KBBkqTXX3/devzq1avr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jx6txYsXW79Xr15d06dP17vvvqsxY8aoU6dOGjp0qD755BNrncjISKWmpmrixIkaOnSoSpcuraeeeirH9osVK6YffvhBr776qp588klduHBB9913n1q2bGkd6Z41a5ZeeOEF1a1bV/7+/nr33XcdfpfcURbjnw/L2+Gvv/5STEyM9XPq1Ck99NBDCgsL04gRI/IizrtCcnKyvL29lZSUdMPHGwAAt4elv8yTF0t/XbeSKG6D47+93Rp9Yx76p2DLi/7JjZvlBqmpqYqNjVVAQIDc3d3zKULciL39Y/fI9ueff25Nrs+cOaPGjRsrLCxMffr0UYMGDZgwDQAAAACA/2N3st2jRw9VrFhRr732mnr37k1yDQAAAADADdg9Qdr06dP10EMPadSoUfL19dVjjz2mCRMm6Jdffsk2bTsAAAAAAPcyu5Ptvn37atGiRTp58qQ2b96sdu3aadu2bWrfvr1KlCih9u3b64MPPsjLWAEAAAAAKBTsTravFxwcrH79+mnx4sXatWuXBg4cqB9//FGvvvpqrgN57733ZLFYNHjwYGtZamqqBgwYoFKlSsnT01OdOnVSQkKCzX5xcXFq3769ihUrJl9fXw0bNkxXr161qRMTE6O6devKzc1NVatW1dy5c7Mdf9q0aapcubLc3d3VqFEjbdu2zWa7PbEAAAAAACDlItk+deqUFi9erH79+ql69ery9/fXBx98oDp16uR6JvLt27fr448/Vu3atW3KhwwZouXLl2vJkiXauHGjTpw4oSeffNK6PSMjQ+3bt1daWpq2bNmiefPmae7cuTZxxMbGqn379goPD9fu3bs1ePBgPf/881q9erW1zuLFixUVFaXo6Gjt3LlTDz74oCIiInTq1Cm7YwEAAAAAIIvdS3/1799fMTExOnjwoIoUKaKGDRuqefPmCg8PV+PGjXM9JX1KSorq1q2r6dOn6+2331ZISIgmTZqkpKQklSlTRgsXLrSup3bgwAFVr15dW7du1UMPPaSVK1fq0Ucf1YkTJ1S2bFlJ0syZM/Xqq6/q9OnTcnV11auvvqoVK1Zo79691mN26dJFiYmJWrVqlSSpUaNGatCggT766CNJUmZmpvz9/fXiiy/qtddesysWe7D0FwDkPZb+Mg9LfxVcLC1VsNE/BVtBmW6Kpb8KL3v7x+6R7V27dqljx45atWqVzp8/r02bNmnMmDFq0aLFbf0HMGDAALVv316tWrWyKd+xY4fS09NtyoOCglSxYkVt3bpVkrR161bVqlXLmmhLUkREhJKTk/X7779b6/yz7YiICGsbaWlp2rFjh00dJycntWrVylrHnlhycuXKFSUnJ9t8AAAAAAB3P7uX/rpZUplbixYt0s6dO7V9+/Zs2+Lj4+Xq6iofHx+b8rJlyyo+Pt5a5/pEO2t71rab1UlOTtbly5d1/vx5ZWRk5FjnwIEDdseSk7Fjx2rUKEZYAAAAAOBeY3eynZmZqd9//121atWSdO1x7bS0NOt2Z2dn9evXT05O9g2WHzt2TC+99JLWrFlz1z4aMXz4cEVFRVm/Jycny9/fPx8jAgAAAIDC5+jRowoICNCuXbsUEhKS3+HYxe5ke9GiRZo5c6Z++OEHSdKwYcPk4+OjIkWuNXHmzBm5u7urd+/edrW3Y8cOnTp1SnXr1rWWZWRk6IcfftBHH32k1atXKy0tTYmJiTYjygkJCfLz85Mk+fn5ZZs1PGuG8Ovr/HPW8ISEBHl5ealo0aJydnaWs7NzjnWub+NWseTEzc1Nbm5udl0PAAAAALgZi+XOLrVsGEMd3qdHjx5KTEzUsmXLbMpjYmIUHh6u8+fPZ3ti+G5ld7I9Z84cDRgwwKZs48aNCgwMlHRtpPuLL76wO9lu2bKl9uzZY1PWs2dPBQUF6dVXX5W/v79cXFy0bt06derUSZJ08OBBxcXFKTQ0VJIUGhqqd955R6dOnZKvr68kac2aNfLy8lJwcLC1zv/+9z+b46xZs8bahqurq+rVq6d169apY8eOkq6N4q9bt04DBw6UJNWrV++WsQAACoaRMn9Sr3sVVxIAUFgYhqGMjAzrYHBBYPcEaQcOHFD9+vVvuD0sLEy//vqr3QcuXry4atasafPx8PBQqVKlVLNmTXl7e6t3796KiorShg0btGPHDvXs2VOhoaHW2b/btGmj4OBgPfvss/r111+1evVqvfnmmxowYIB1RLlv3746cuSIXnnlFR04cEDTp0/Xl19+qSFDhlhjiYqK0qeffqp58+Zp//796tevny5evKiePXtKkl2xAAAAAABu7uLFi/Ly8tJ///tfm/Jly5bJw8NDFy5ckCRt27ZNderUkbu7u+rXr69du3bZ1I+JiZHFYtHKlStVr149ubm56ccff9SVK1c0aNAg+fr6yt3dXQ8//HCOc4TdCXan/adPn7b5fuTIEZUqVcr63cXFRRcvXjQvMkkTJ06Uk5OTOnXqpCtXrigiIkLTp0+3bnd2dtZ3332nfv36KTQ0VB4eHoqMjNTo0aOtdQICArRixQoNGTJEkydPVoUKFfTZZ58pIiLCWqdz5846ffq0RowYofj4eIWEhGjVqlU2k6bdKhYAAAAAwM15eHioS5cumjNnjnVZZUnW78WLF1dKSooeffRRtW7dWl988YViY2P10ksv5djea6+9pg8++ECBgYEqUaKEXnnlFS1dulTz5s1TpUqVNH78eEVEROjPP/9UyZIl79RpSnJgne1KlSppxowZateuXY7bly9froEDB+qvv/4yNcC7CetsA0DeYy1a87BWcMFF3xRs9E/BVpjX2S4s72x/8cUX2SbBzsjIUGpqqs6fP68//vhDjRs31rFjx1SuXDmdOnVK9913n9auXauwsDB98sknev3113X8+HFrOzNnzlS/fv2sE6RlvQO+bNkydejQQdK1UfMSJUpo7ty56tatmyQpPT1dlStX1uDBgzVs2LDbvCLXmL7OdsuWLfXOO+/kuM0wDI0dO1YtW7Z0PFIAAAAAwF0jPDxcu3fvtvl89tln1u0NGzZUjRo1NG/ePEnSF198oUqVKqlZs2aSpP3796t27do2ieyN5sq6/lXnw4cPKz09XU2aNLGWubi4qGHDhtq/f7+p52gPux8jf+ONN1S3bl01atRIQ4cO1f333y/p2kRhH3zwgQ4ePKjPP/88zwIFAAAAABR8Hh4eqlq1qk3Z8ePHbb4///zzmjZtml577TXNmTNHPXv2lCUXj3B4eHjcVqx5ye6R7SpVqmjNmjW6cOGCOnfurLp166pu3brq0qWLUlJS9P3332e7oAAAAAAA/NMzzzyjv/76S1OmTNG+ffsUGRlp3Va9enX99ttvSk1NtZb99NNPt2yzSpUqcnV11ebNm61l6enp2r59u3W1qjvJoXnRGzZsqH379mn37t36448/JEnVqlVTnTp18iQ4AAAAAMDdp0SJEnryySc1bNgwtWnTRhUqVLBu69atm9544w316dNHw4cP19GjR/XBB7d+X93Dw0P9+vXTsGHDVLJkSVWsWFHjx4/XpUuX7F6i2ky5WoQsJCREISEhJocCAAAAALiR3ExYVpD17t1bCxcuVK9evWzKPT09tXz5cvXt21d16tRRcHCwxo0bp06dOt2yzffee0+ZmZl69tlndeHCBdWvX1+rV69WiRIl8uo0bsiu2cjfe+89vfTSSypatOgtG/z555915swZtW/f3pQA7ybMRg4AeY8Ze83DjMoFF31TsNE/BVthno38bjN//nwNGTJEJ06ckKura36HYzdTZyPft2+fKlasqP79+2vlypU2a25fvXpVv/32m6ZPn67GjRurc+fOKl68+O2fAQAAAADgrnPp0iUdPnxY7733nv79738XqkTbEXYl259//rnWrl2r9PR0devWTX5+fnJ1dVXx4sXl5uamOnXqaPbs2Xruued04MAB65TtAAAAAABcb/z48QoKCpKfn5+GDx+e3+HkGbseI79eZmamfvvtN/3111+6fPmySpcurZCQEJUuXTqvYrxr8Bg5AOQ9HrU0D4/CFlz0TcFG/xRsPEaO22Vv/zg8QZqTkxMTpAEAAAAAcBN2r7MNAAAAAADsQ7INAAAAAIDJSLYBAAAAADAZyTYAAAAAACYj2QYAAAAAwGQOJ9sXL17UW2+9pcaNG6tq1aoKDAy0+QAAAAAAkJcqV66sSZMm5XcYN+Xw0l/PP/+8Nm7cqGeffVblypWThUX/AAAAACDP3ency8jlouTx8fF65513tGLFCv3999/y9fVVSEiIBg8erJYtW5ocZcHlcLK9cuVKrVixQk2aNMmLeAAAAAAAhdTRo0fVpEkT+fj46P3331etWrWUnp6u1atXa8CAATpw4EB+h3jHOPwYeYkSJVSyZMm8iAUAAAAAUIj1799fFotF27ZtU6dOnXT//ferRo0aioqK0k8//SRJiouLU4cOHeTp6SkvLy89/fTTSkhIsLZx+PBhdejQQWXLlpWnp6caNGigtWvX5tcp5ZrDyfaYMWM0YsQIXbp0KS/iAQAAAAAUQufOndOqVas0YMAAeXh4ZNvu4+OjzMxMdejQQefOndPGjRu1Zs0aHTlyRJ07d7bWS0lJUbt27bRu3Trt2rVLbdu21WOPPaa4uLg7eTq3zeHHyCdMmKDDhw+rbNmyqly5slxcXGy279y507TgAAAAAACFw59//inDMBQUFHTDOuvWrdOePXsUGxsrf39/SdLnn3+uGjVqaPv27WrQoIEefPBBPfjgg9Z9xowZo6+//lrffvutBg4cmOfnYRaHk+2OHTvmQRgAAAAAgMLMngnV9u/fL39/f2uiLUnBwcHy8fHR/v371aBBA6WkpGjkyJFasWKFTp48qatXr+ry5ct3/8h2dHR0XsQBAAAAACjEqlWrJovFctuToA0dOlRr1qzRBx98oKpVq6po0aJ66qmnlJaWZlKkd4bDyXaWHTt2aP/+/ZKkGjVqqE6dOqYFBQAAAAAoXEqWLKmIiAhNmzZNgwYNyvbedmJioqpXr65jx47p2LFj1tHtffv2KTExUcHBwZKkzZs3q0ePHnriiSckXXuH++jRo3f0XMzgcLJ96tQpdenSRTExMfLx8ZF07aKFh4dr0aJFKlOmjNkxAkCBMsoyKr9DuGtEGzwtBQDA3WTatGlq0qSJGjZsqNGjR6t27dq6evWq1qxZoxkzZmjfvn2qVauWunfvrkmTJunq1avq37+/wsLCVL9+fUnXRsi/+uorPfbYY7JYLHrrrbeUmZmZz2fmOIdnI3/xxRd14cIF/f777zp37pzOnTunvXv3Kjk5WYMGDcqLGAEAAADgnmcYxh395EZgYKB27typ8PBwvfzyy6pZs6Zat26tdevWacaMGbJYLPrmm29UokQJNWvWTK1atVJgYKAWL15sbePDDz9UiRIl1LhxYz322GOKiIhQ3bp1zbqMd4zFcPAqent7a+3atWrQoIFN+bZt29SmTRslJiaaGd9dJTk5Wd7e3kpKSpKXl1d+hwMglxjZNk9ejGxbLKY3ec/K5e9ZN0X/mIO+Kdjon4ItL/onN26WG6Smpio2NlYBAQFyd3fPpwhxI/b2j8Mj25mZmdmW+5IkFxeXQjm0DwAAAACA2RxOtlu0aKGXXnpJJ06csJb9/fffGjJkiFq2bGlqcAAAAAAAFEYOJ9sfffSRkpOTVblyZVWpUkVVqlRRQECAkpOTNXXq1LyIEQAAAACAQsXh2cj9/f21c+dOrV271rp+WvXq1dWqVSvTgwMAAAAAoDDK1TrbFotFrVu3VuvWrc2OBwAAAACAQs+uZHvKlCl64YUX5O7urilTpty0Lst/AQAAAADudXYl2xMnTlT37t3l7u6uiRMn3rCexWIh2QYAAAAA3PPsSrZjY2Nz/DcA3ItGyvy1oe9VXEkAAHC3cng28tGjR+vSpUvZyi9fvqzRo0ebEhQAAAAAAIWZw8n2qFGjlJKSkq380qVLGjVqlClBAQAAAABQmDk8G7lhGLJYLNnKf/31V5UsWdKUoAAAwN3JWJD9dwjkhpHfAQDIB3v37r2jx6tZs2au9ouPj9c777yjFStW6O+//5avr69CQkI0ePBgtWzZUpK0a9cuvfvuu/rhhx+UlJQkf39/NW/eXMOGDdP9999vbWvp0qWaNm2adu3apdTUVFWsWFFNmjTRiy++qKSkJIWHh980lg0bNqh58+a5Oo/bZffIdokSJVSyZElZLBbdf//9KlmypPXj7e2t1q1b6+mnn87LWAEAAAAABdjRo0dVr149rV+/Xu+//7727NmjVatWKTw8XAMGDJAkfffdd3rooYd05coVLViwQPv379cXX3whb29vvfXWW9a2Xn31VXXu3FkhISH69ttvdfDgQS1cuFCBgYEaPny4GjdurJMnT1o/Tz/9tNq2bWtT1rhx4/y6FPaPbE+aNEmGYahXr14aNWqUvL29rdtcXV1VuXJlhYaG5kmQAAAAAICCr3///rJYLNq2bZs8PDys5TVq1FCvXr106dIl9ezZU+3atdPXX39t3R4QEKBGjRopMTFRkvTTTz9p/Pjxmjx5ss2KVxUrVlS9evWsT1z7+flZtxUtWlRXrlyxKctPdifbkZGRkq5dhMaNG8vFxSXPggIAAAAAFC7nzp3TqlWr9M4779gk2ll8fHz09ddf68yZM3rllVdybMPHx0eS9J///Eeenp7q379/jvVyerW5oHF4grSwsDBrop2amqrk5GSbDwAAAADg3vPnn3/KMAwFBQXdsM6hQ4ck6aZ1JOmPP/5QYGCgihT5/+PDH374oTw9Pa2fpKQkcwLPIw4n25cuXdLAgQPl6+srDw8PlShRwuYDAAAAALj3GMatJ2+0p86N9OrVS7t379bHH3+sixcv3lZbd4LDyfawYcO0fv16zZgxQ25ubvrss880atQolS9fXp9//nlexAgAAAAAKOCqVasmi8WiAwcO3LBO1kzjN6uT1daRI0eUnp5uLfPx8VHVqlV13333mRNwHnM42V6+fLmmT5+uTp06qUiRImratKnefPNNvfvuu1qwYEFexAgAAAAAKOBKliypiIgITZs2TRcvXsy2PTExUW3atFHp0qU1fvz4HNvImiCta9euSklJ0fTp0/My5DzlcLJ97tw5BQYGSpK8vLx07tw5SdLDDz+sH374wdzoAAAAAACFxrRp05SRkaGGDRtq6dKlOnTokPbv368pU6YoNDRUHh4e+uyzz7RixQo9/vjjWrt2rY4ePapffvlFr7zyivr27StJCg0N1csvv6yXX35ZUVFR+vHHH/XXX3/pp59+0qxZs2SxWOTk5HA6e0fZPRt5lsDAQMXGxqpixYoKCgrSl19+qYYNG2r58uXWmeMAAAAAAOaqWbNmfodwS4GBgdq5c6feeecdvfzyyzp58qTKlCmjevXqacaMGZKkDh06aMuWLRo7dqy6deum5ORk+fv7q0WLFnr77betbX3wwQdq2LChZsyYodmzZ+vSpUsqW7asmjVrpq1bt8rLyyu/TtMuFsPBt8onTpwoZ2dnDRo0SGvXrtVjjz0mwzCUnp6uDz/8UC+99FJexVroJScny9vbW0lJSQX+PwwAN1YIVpooNPJiXhP6xzx5Mu/MQjrIFN3M7xzuHfPws61gKyhzat0sN0hNTVVsbKwCAgLk7u6eTxHiRuztH4dHtocMGWL9d6tWrXTgwAHt2LFDVatWVe3atXMXLQAAAAAAdxGHHnJPT09Xy5YtrWujSVKlSpX05JNPkmgDAAAAAPB/HEq2XVxc9Ntvv+VVLAAAAAAA3BUcnr7tmWee0axZs/IiFgAAAAAA7goOv7N99epVzZ49W2vXrlW9evXk4eFhs/3DDz80LTgAAAAAAAojh5PtvXv3qm7dupKkP/74w2abhWkSAQAAAABwPNnesGFDXsQBAAAAAMBdw+F3trP8+eefWr16tS5fvixJcnC5bknSjBkzVLt2bXl5ecnLy0uhoaFauXKldXtqaqoGDBigUqVKydPTU506dVJCQoJNG3FxcWrfvr2KFSsmX19fDRs2TFevXrWpExMTo7p168rNzU1Vq1bV3Llzs8Uybdo0Va5cWe7u7mrUqJG2bdtms92eWAAAAAAAkHKRbJ89e1YtW7bU/fffr3bt2unkyZOSpN69e+vll192qK0KFSrovffe044dO/TLL7+oRYsW6tChg37//XdJ19b0Xr58uZYsWaKNGzfqxIkTevLJJ637Z2RkqH379kpLS9OWLVs0b948zZ07VyNGjLDWiY2NVfv27RUeHq7du3dr8ODBev7557V69WprncWLFysqKkrR0dHauXOnHnzwQUVEROjUqVPWOreKBQAAAACALBbDwSHp5557TqdOndJnn32m6tWr69dff1VgYKBWr16tqKgoa6KcWyVLltT777+vp556SmXKlNHChQv11FNPSZIOHDig6tWra+vWrXrooYe0cuVKPfroozpx4oTKli0rSZo5c6ZeffVVnT59Wq6urnr11Ve1YsUK7d2713qMLl26KDExUatWrZIkNWrUSA0aNNBHH30kScrMzJS/v79efPFFvfbaa0pKSrplLDm5cuWKrly5Yv2enJwsf39/JSUlycvL67auE+5+oyyj8juEu0a0EW1qe0xPYZ5cPBR1S/SPefKif7SQDjJFN/M7h3vHPPxsK9jy5GdbLiQnJ8vb2zvH3CA1NVWxsbEKCAiQu7t7PkWYN44ePaqAgADt2rVLISEhprQZExOj8PBwnT9/Xj4+Pqa0eTP29o/D72x///33Wr16tSpUqGBTXq1aNf3111+OR/p/MjIytGTJEl28eFGhoaHasWOH0tPT1apVK2udoKAgVaxY0Zrgbt26VbVq1bIm2pIUERGhfv366ffff1edOnW0detWmzay6gwePFiSlJaWph07dmj48OHW7U5OTmrVqpW2bt0qSXbFkpOxY8dq1CgSJgAAUPAZC8jmzFNAsjncdSwxMXf0eEbz5g7v06NHD82bN8/6vWTJkmrQoIHGjx+v2rVry9/fXydPnlTp0qVNjLRgcvgx8osXL6pYsWLZys+dOyc3NzeHA9izZ488PT3l5uamvn376uuvv1ZwcLDi4+Pl6uqa7S8TZcuWVXx8vCQpPj7eJtHO2p617WZ1kpOTdfnyZZ05c0YZGRk51rm+jVvFkpPhw4crKSnJ+jl27Jh9FwUAAAAACqm2bdvq5MmTOnnypNatW6ciRYro0UcflSQ5OzvLz89PRYo4PO5b6DicbDdt2lSff/659bvFYlFmZqbGjx+v8PBwhwN44IEHtHv3bv3888/q16+fIiMjtW/fPofbKYjc3Nysk79lfQAAAADgbubm5iY/Pz/5+fkpJCREr732mo4dO6bTp0/r6NGjslgs2r17t7X+xo0b1bBhQ7m5ualcuXJ67bXXbCa9zszM1NixYxUQEKCiRYvqwQcf1H//+9+bxvDjjz+qadOmKlq0qPz9/TVo0CBdvHgxr045Rw7/OWH8+PFq2bKlfvnlF6WlpemVV17R77//rnPnzmnz5s0OB+Dq6qqqVatKkurVq6ft27dr8uTJ6ty5s9LS0pSYmGgzopyQkCA/Pz9Jkp+fX7ZZw7NmCL++zj9nDU9ISJCXl5eKFi0qZ2dnOTs751jn+jZuFQtgtpEy9z3jexlXEgAAIH+kpKToiy++UNWqVVWqVKlsCe/ff/+tdu3aqUePHvr888914MAB9enTR+7u7ho5cqSka6/nfvHFF5o5c6aqVaumH374Qc8884zKlCmjsLCwbMc8fPiw2rZtq7fffluzZ8/W6dOnNXDgQA0cOFBz5sy5E6ctKRcj2zVr1tQff/yhhx9+WB06dNDFixf15JNPateuXapSpcptB5SZmakrV66oXr16cnFx0bp166zbDh48qLi4OIWGhkqSQkNDtWfPHptZw9esWSMvLy8FBwdb61zfRladrDZcXV1Vr149mzqZmZlat26dtY49sQAAAAAApO+++06enp7y9PRU8eLF9e2332rx4sVycsqefk6fPl3+/v766KOPFBQUpI4dO2rUqFGaMGGCNTd89913NXv2bEVERCgwMFA9evTQM888o48//jjH448dO1bdu3fX4MGDVa1aNTVu3FhTpkzR559/rtTU1Lw+fatcPSjv7e2tN95447YPPnz4cD3yyCOqWLGiLly4oIULFyomJkarV6+Wt7e3evfuraioKJUsWVJeXl568cUXFRoaap2QrE2bNgoODtazzz6r8ePHKz4+Xm+++aYGDBhgfX+8b9+++uijj/TKK6+oV69eWr9+vb788kutWLHCGkdUVJQiIyNVv359NWzYUJMmTdLFixfVs2dP6/neKhYAAAAAgBQeHq4ZM2ZIks6fP6/p06frkUceyfZUsiTt379foaGhslw35X6TJk2UkpKi48eP68KFC7p06ZJat25ts19aWprq1KmT4/F//fVX/fbbb1qwYIG1zDAMZWZmKjY2VtWrVzfjNG8pV8l2YmKitm3bplOnTikzM9Nm23PPPWd3O6dOndJzzz2nkydPytvbW7Vr19bq1autF3LixIlycnJSp06ddOXKFUVERGj69OnW/Z2dnfXdd9+pX79+Cg0NlYeHhyIjIzV69GhrnYCAAK1YsUJDhgzR5MmTVaFCBX322WeKiIiw1uncubNOnz6tESNGKD4+XiEhIVq1apXNpGm3igUAAAAAIHl4eFhfFZakzz77TN7e3vr000/1/PPPO9RWSkqKJGnFihW67777bLbdaILulJQU/fvf/9agQYOybatYsaJDx78dDifb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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "y2020_Nuclear_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCENUCLEAR')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum()\n", + "y2025_Nuclear_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCENUCLEAR')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum()\n", + "y2030_Nuclear_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCENUCLEAR')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum()\n", + "y2035_Nuclear_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCENUCLEAR')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum()\n", + "y2040_Nuclear_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCENUCLEAR')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum()\n", + "y2045_Nuclear_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCENUCLEAR')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum()\n", + "y2050_Nuclear_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCENUCLEAR')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum()\n", + "\n", + "y2020_solarPV_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCESOPHVCEWT')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum()\n", + "y2025_solarPV_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCESOPHVCEWT')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum()\n", + "y2030_solarPV_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCESOPHVCEWT')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum()\n", + "y2035_solarPV_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCESOPHVCEWT')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum()\n", + "y2040_solarPV_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCESOPHVCEWT')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum()\n", + "y2045_solarPV_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCESOPHVCEWT')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum()\n", + "y2050_solarPV_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCESOPHVCEWT')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum()\n", + "\n", + "y2020solarTELC_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCESOTELCE')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum()\n", + "y2025solarTELC_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCESOTELCE')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum()\n", + "y2030solarTELC_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCESOTELCE')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum()\n", + "y2035solarTELC_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCESOTELCE')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum()\n", + "y2040solarTELC_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCESOTELCE')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum()\n", + "y2045solarTELC_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCESOTELCE')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum()\n", + "y2050solarTELC_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCESOTELCE')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum()\n", + "\n", + "y2020_wind_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEWINDON')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum()\n", + "y2025_wind_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEWINDON')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum()\n", + "y2030_wind_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEWINDON')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum()\n", + "y2035_wind_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEWINDON')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum()\n", + "y2040_wind_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEWINDON')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum()\n", + "y2045_wind_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEWINDON')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum()\n", + "y2050_wind_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEWINDON')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum()\n", + "\n", + "y2020hydro_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEHYRURIV')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEHYRSCAP')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEMINIHYDR')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum()+ data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEHYPSTOR')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2020')].vQCESecOUT.sum()\n", + "y2025hydro_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEHYRURIV')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEHYRSCAP')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEMINIHYDR')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum()+ data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEHYPSTOR')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2025')].vQCESecOUT.sum()\n", + "y2030hydro_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEHYRURIV')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEHYRSCAP')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEMINIHYDR')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum()+ data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEHYPSTOR')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2030')].vQCESecOUT.sum()\n", + "y2035hydro_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEHYRURIV')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEHYRSCAP')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEMINIHYDR')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum()+ data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEHYPSTOR')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2035')].vQCESecOUT.sum()\n", + "y2040hydro_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEHYRURIV')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEHYRSCAP')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEMINIHYDR')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum()+ data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEHYPSTOR')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2040')].vQCESecOUT.sum()\n", + "y2045hydro_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEHYRURIV')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEHYRSCAP')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEMINIHYDR')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum()+ data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEHYPSTOR')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2045')].vQCESecOUT.sum()\n", + "y2050hydro_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEHYRURIV')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEHYRSCAP')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEMINIHYDR')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum()+ data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEHYPSTOR')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2050')].vQCESecOUT.sum()\n", + "\n", + "y2020coalCE_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOTRA')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOIGCC')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCPC')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCCCS')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum()\n", + "y2025coalCE_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOTRA')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOIGCC')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCPC')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCCCS')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum()\n", + "y2030coalCE_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOTRA')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOIGCC')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCPC')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCCCS')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum()\n", + "y2035coalCE_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOTRA')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOIGCC')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCPC')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCCCS')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum()\n", + "y2040coalCE_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOTRA')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOIGCC')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCPC')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCCCS')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum()\n", + "y2045coalCE_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOTRA')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOIGCC')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCPC')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCCCS')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum()\n", + "y2050coalCE_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOTRA')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOIGCC')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCPC')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum() + data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCCCS')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum()\n", + "\n", + "y2020gasCE_TEELECE = data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2020')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2020')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2020')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2020')].vQCESecOUT.sum()\n", + "y2025gasCE_TEELECE = data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2025')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2025')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2025')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2025')].vQCESecOUT.sum()\n", + "y2030gasCE_TEELECE = data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2030')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2030')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2030')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2030')].vQCESecOUT.sum()\n", + "y2035gasCE_TEELECE = data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2035')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2035')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2035')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2035')].vQCESecOUT.sum()\n", + "y2040gasCE_TEELECE = data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2040')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2040')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2040')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2040')].vQCESecOUT.sum()\n", + "y2045gasCE_TEELECE = data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2045')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2045')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2045')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2045')].vQCESecOUT.sum()\n", + "y2050gasCE_TEELECE = data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2050')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2050')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCESecOUT'].sYear=='y2050')].vQCESecOUT.sum() + data_results['vQCESecOUT'][(data_results['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (data_results['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2050')].vQCESecOUT.sum()\n", + "\n", + "\n", + "y2020bioeleCE_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEBIOELECE')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum()\n", + "y2025bioeleCE_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEBIOELECE')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum()\n", + "y2030bioeleCE_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEBIOELECE')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum()\n", + "y2035bioeleCE_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEBIOELECE')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum()\n", + "y2040bioeleCE_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEBIOELECE')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum()\n", + "y2045bioeleCE_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEBIOELECE')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum()\n", + "y2050bioeleCE_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCEBIOELECE')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum()\n", + "\n", + "y2020sldwast_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCESLDWAST')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum()\n", + "y2025sldwast_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCESLDWAST')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum()\n", + "y2030sldwast_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCESLDWAST')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum()\n", + "y2035sldwast_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCESLDWAST')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum()\n", + "y2040sldwast_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCESLDWAST')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum()\n", + "y2045sldwast_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCESLDWAST')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum()\n", + "y2050sldwast_TEELECE = data_results['vQCEPriOUT'][(data_results['vQCEPriOUT'].sCE.str.startswith('sCESLDWAST')) & (data_results['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (data_results['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum()\n", + "\n", + "\n", + "# Graph\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "Nuclear_TEELECE = [y2020_Nuclear_TEELECE, y2025_Nuclear_TEELECE, y2030_Nuclear_TEELECE, y2035_Nuclear_TEELECE, y2040_Nuclear_TEELECE, y2045_Nuclear_TEELECE, y2050_Nuclear_TEELECE]\n", + "Hydro_TEELECE = [y2020hydro_TEELECE, y2025hydro_TEELECE, y2030hydro_TEELECE, y2035hydro_TEELECE, y2040hydro_TEELECE, y2045hydro_TEELECE, y2050hydro_TEELECE]\n", + "Coal_TEELECE = [y2020coalCE_TEELECE, y2025coalCE_TEELECE, y2030coalCE_TEELECE, y2035coalCE_TEELECE, y2040coalCE_TEELECE, y2045coalCE_TEELECE, y2050coalCE_TEELECE]\n", + "Gas_TEELECE = [y2020gasCE_TEELECE, y2025gasCE_TEELECE, y2030gasCE_TEELECE, y2035gasCE_TEELECE, y2040gasCE_TEELECE, y2045gasCE_TEELECE, y2050gasCE_TEELECE]\n", + "Bioele_TEELECE = [y2020bioeleCE_TEELECE, y2025bioeleCE_TEELECE, y2030bioeleCE_TEELECE, y2035bioeleCE_TEELECE, y2040bioeleCE_TEELECE, y2045bioeleCE_TEELECE, y2050bioeleCE_TEELECE]\n", + "Sldwast_TEELECE = [y2020sldwast_TEELECE, y2025sldwast_TEELECE, y2030sldwast_TEELECE, y2035sldwast_TEELECE, y2040sldwast_TEELECE, y2045sldwast_TEELECE, y2050sldwast_TEELECE]\n", + "SolarPV_TEELECE = [y2020_solarPV_TEELECE, y2025_solarPV_TEELECE, y2030_solarPV_TEELECE, y2035_solarPV_TEELECE, y2040_solarPV_TEELECE, y2045_solarPV_TEELECE, y2050_solarPV_TEELECE]\n", + "Wind_TEELECE = [y2020_wind_TEELECE, y2025_wind_TEELECE, y2030_wind_TEELECE, y2035_wind_TEELECE, y2040_wind_TEELECE, y2045_wind_TEELECE, y2050_wind_TEELECE]\n", + "SolarTE_TEELECE = [y2020solarTELC_TEELECE, y2025solarTELC_TEELECE, y2030solarTELC_TEELECE, y2035solarTELC_TEELECE, y2040solarTELC_TEELECE, y2045solarTELC_TEELECE, y2050solarTELC_TEELECE]\n", + "\n", + "# Use the same data to make a stacked bar chart\n", + "plt.figure(figsize=(10, 5))\n", + "plt.bar(years, Nuclear_TEELECE, color='y', label='Nuclear')\n", + "plt.bar(years, Hydro_TEELECE, bottom=Nuclear_TEELECE, color='darkblue', label='Hydro')\n", + "plt.bar(years, Coal_TEELECE, bottom=[sum(x) for x in zip(Nuclear_TEELECE, Hydro_TEELECE)], color='k', label='Coal')\n", + "plt.bar(years, Gas_TEELECE, bottom=[sum(x) for x in zip(Nuclear_TEELECE, Hydro_TEELECE, Coal_TEELECE)], color='lightgrey', label='CCGT')\n", + "plt.bar(years, Bioele_TEELECE, bottom=[sum(x) for x in zip(Nuclear_TEELECE, Hydro_TEELECE, Coal_TEELECE, Gas_TEELECE)], color='c', label='Bioele')\n", + "plt.bar(years, Sldwast_TEELECE, bottom=[sum(x) for x in zip(Nuclear_TEELECE, Hydro_TEELECE, Coal_TEELECE, Gas_TEELECE, Bioele_TEELECE)], color='m', label='Sldwast')\n", + "plt.bar(years, SolarPV_TEELECE, bottom=[sum(x) for x in zip(Nuclear_TEELECE, Hydro_TEELECE, Coal_TEELECE, Gas_TEELECE, Bioele_TEELECE, Sldwast_TEELECE)], color='orange', label='SolarPV')\n", + "plt.bar(years, Wind_TEELECE, bottom=[sum(x) for x in zip(Nuclear_TEELECE, Hydro_TEELECE, Coal_TEELECE, Gas_TEELECE, Bioele_TEELECE, Sldwast_TEELECE, SolarPV_TEELECE)], color='blue', label='Wind')\n", + "plt.bar(years, SolarTE_TEELECE, bottom=[sum(x) for x in zip(Nuclear_TEELECE, Hydro_TEELECE, Coal_TEELECE, Gas_TEELECE, Bioele_TEELECE, Sldwast_TEELECE, SolarPV_TEELECE, Wind_TEELECE)], color='purple', label='SolarTE')\n", + "plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))\n", + "plt.title('Electricity Generation Mix for TEELECE')\n", + "plt.xlabel('Year')\n", + "plt.ylabel('Electricity Generation (GWh)')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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xeGYmBh88803OHnyJHr06IHvv/8eAQEBmDRpUpnzCIJgd4zjx4+/a5vvv/8egiBYh+tW9FolJBIJRowYgVWrViE3NxdeXl4AigtqPfDAA+UWXyqh0+kAoEyvtlartQ6bL3H8+HF07twZu3fvhkajwbPPPmvznkqlUnTr1g379u0rc51be1N79uxpUxzru+++g4+PD/r3729zzk6dOsHT0xP79u3Dc889Z90eHh6OmJiYMtcpPW9bq9XCaDQiOjoau3btglarhY+Pz23fi/L88ccfyMjIwLx582zmcg8aNAgtW7bE9u3brUXz7L1Xezz33HNYsGAB1q1bh//85z+QSqV44okncOLECbuOd3d3x6ZNm9CrVy/06tULx44dw6effopGjRo5FEeJPXv2wGAwYMqUKTZF+8aOHYvXX38d27dvx6hRo6zblUqlzWtnmjNnDnr27Flmu7+/v83rbt264Z133inT7nbV3u/1uiU/SyU/f/Zy9PcaERE5H5NtIrrvde3a1aFCQpmZmdBoNPjoo49uO4y3pBhUYmIiWrRoAZms4r9uZTKZXfMxExMTUb9+/TLJwb148cUXsXTpUvz444948cUXceHCBZw4cQIbNmy443EliUFeXp7Ndk9PT+zevRsA8Msvv+Ddd9+17ktISABQPFy5PN7e3javS+akl+bn52czFzshIQFarfa2w6RLvk8lbvcBwuHDhzF37lwcOXIEBQUFNvsqkmxfuXIFAMqd996yZUscOnTIZps992qP4cOHY/r06dixYwe+/PJLDB482OEkrkePHhg/fjzWrl2LmJgYjB492qHjS7vd+6BQKNC4cWPr/hIly8dVhjZt2qBfv353bRcQEGBXO2ddt+TffW5urkPndfT3GhEROR+TbSIiB5UUmHr++ecRGxtbbpu2bds67XpKpdKm168qRUZGolOnTvjiiy/w4osv4osvvoBCoSi3oFZpLVu2BACcPXvWZrtMJrMmFqmpqTb7St7XLVu2oF69emXOeesHFvb00lksFgQFBeHLL78sd/+tCWx5lccTExPRt29ftGzZEu+//z5CQkKgUCjwv//9DytWrKjQ8muOclaPZHBwMHr37o3ly5fj8OHDZSqQ26OoqMg67zsxMbHciuCVxRmV4Wuakp+lv/76y1pDgIiIagYm20REDgoMDISXlxfMZvNde7iaNGmC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AtU+TLarUMnQcW9vbybbRERERETE6aW1GCcHEBERERERETkZk20iIiIiIiIiJ2OyTURERERERORkTLaJiIiIiIiInIzJNhEREREREZGTMdkmIiIiIiIicjIm20REREREREROxmSbiIiIiIiIyMmYbBMRERERERE5GZNtIiIiIiIiIidjsk1ERERERETkZEy2iYiIiIiIiJyMyTYRERERERGRkzHZJiIiIiIiInIyJttERERERERETiZzdQBERERERET3ymwugsGQjqKiDBQZMmAoyrB9bsiAt3d7REYscXWodJ9gsk1ERERERNWW2axHUVE6DIZMFBWl2yTPRUUZ1u0mk+6u53J3b1wFERMVY7JNRERERERVzmwuvJk8Z8Jw82tRUToMRZkoMqSjqCgTBkM6TKZcV4dKVCFMtomIiIiIyGnM5oLiJPpm0mwo/bVUUm0257k6VKJKxWSbiIiIiIjuymTKh+Hm0G3bYd2ZpV5nMIkmuonJNhERERHRfcxkyrs59/mWgmK3JNJmc76rQyWqUZhsExERERHVQiZTbplq3EVFZYuLMYkmqhxMtomIiIiIahCjUXezF/rOxcUslkJXh0p0X2OyTURERERUDRiN2tuuD126R9pi0bs6VCKyA5NtIiIiIqJKZDRqbpkLXU4ibchkEk1UyzDZJiIiIiKqAKMx52ZlbtviYqVfFyfRRa4OlYhcgMk2EREREREAUTTDZMqF0aiFyaQt7pG+zVDu4iTa4OqQiagaY7JNRERERLWG2VxUnCibtDCZdDAZdaWea2E06W77vLgqt+jqWyCiWoLJNhERERFVG6IowmzOu9m7fDNRNupKPdcW9z6Xl0CbtOxtJqJqg8k2ERERETmVxWKEyaS1HZJ9s5f5n+elk2YtTMaS57kALK6+BSKie8Zkm4iIiIjKMJnyb/YW66y9zKWTZmvPss3+4udc35mIiMk2ERERUa10a7Evay+ydXh2+Yly8fNciKLR1bdARFSjMdkmIiIiqqZY7IuIqOZisk1ERERUSe5a7OtOCTSLfRER1WhMtomIiIjugcViwrVrX0KjOV6m2JfZnAdRNLs6RCIicgEm20REREQVpFYfxMWEd1BQcMnVoRARUTXDZJuIiIjIQQUFV5BwaRGysva4OhQiIqqmmGwTERER2clkykfylXW4evUzzqcmIqI7YrJNRERE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sADJycno27cvZLLiwy0WC1588UUsWrTI6QESVTfWImVuPvCTskgZERERERGV5XCyrVAosHXrVixYsABnzpyBm5sb2rRpg9DQUIcvvnjxYvzwww+Ij4+Hm5sbHnjgASxduhQtWrSwttHr9Xj11VfxzTffoKioCDExMVi3bh3q1q1rbZOSkoLx48dj37598PT0RGxsLBYvXmz9MAAA4uLiMG3aNPz9998ICQnBm2++iZEjR9rEs3btWrz77rtIS0tDu3btsHr1anTt2tWhWKj2kMvlqOPjD3+VN3ytRcoU8NBIIClgUk1EREREVWvevHm17npxcXHo06cPcnJy4OvrW+HzjBw5EhqNBtu2bXNabPdKUtEDmzdvjqeffhqDBw+uUKINFA8/nzBhAn7//Xfs3r0bRqMRAwYMQH5+vrXN1KlT8dNPP+G7777D/v37cf36dTz55JPW/WazGYMGDYLBYMBvv/2GzZs3Y9OmTZgzZ461TVJSEgYNGoQ+ffrg9OnTmDJlCl566SXs2rXL2mbr1q2YNm0a5s6di5MnT6Jdu3aIiYlBRkaG3bFQzaRSqdAgqD7ahLREz4ad8GhQDzyn7I0X83picGprPHCpESIT/NHgihu8sqWQWJhoExERERHdasOGDfDy8oLJZLJuy8vLg1wuR+/evW3axsXFQRAEBAcH48aNG/Dx8aniaCufXT3b06ZNw4IFC+Dh4YFp06bdse37779v98V37txp83rTpk0ICgrCiRMn0KtXL2i1Wnz66af46quv8NBDDwEoXuc7IiICv//+O7p3745ffvkF586dw549e1C3bl20b98eCxYswMyZMzFv3jwoFAps2LAB4eHhWL58OQAgIiIChw4dwooVKxATE2ONe+zYsRg1ahSA4n8o27dvx2effYZZs2bZFQtVbzZFykQP+BSq4KWRQaWRABpXR0dEREREVLP16dMHeXl5+OOPP6z50cGDB1GvXj0cPXoUer0eKpUKALBv3z40atTIZlRzbWNXz/apU6dgNBoBACdPnsSpU6fKfZw+ffqegtFqi8sy+/v7AwBOnDgBo9GIfv36Wdu0bNkSjRo1wpEjRwAAR44cQZs2bWyGcsfExECn0+Hvv/+2til9jpI2JecwGAw4ceKETRuJRIJ+/fpZ29gTy62Kioqg0+lsHlS5BEGAr7cPmtQPQ+dGbdC3QTc8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RFRrSBw9YPLkyVi1alWZ7WvWrMGUKVOcERMRERERERFRjeZwsv3999+jR48eZbY/8MAD+M9//uOUoIiI/r+9ew+TojrQP/6eqr7N/QozjAw3IdwRFSVEE0NEMWYTyfrsGtTEGCOr4kaXXAxuIprdTVZ9XDU+KokxmGST1eQhElcjLoJ30R9qUFAhihJFmQFmmPutu+v8/ujLTMOgDPR0z+X7eZ5+uurUqdOn51g471TVKQAAAGAw63PYrqurS5mJPKGwsFD79u1LS6cAAAAAABjM+hy2J06cqLVr1x5U/uijj2rChAlp6RQAAAAAAINZnydIW7Zsma688krt3btXn/vc5yRJ69ev1y233KLbbrst3f0DAAAAAEhav+HYjH7e6Z/bkdHPk6Trr79ea9as0ebNmzP+2enW5zPb3/jGN3TLLbfo3nvv1fz58zV//nz993//t+6++25deuml/dFHAAAAAMAgsHfvXl1++eUaM2aMgsGgKisrtXDhQj333HMZ68P1118vY8xHviTp61//eq/bzjrrrLT0o89ntiXp8ssv1+WXX669e/cqJydH+fn5aekMAAAAAGDwOvfcc9XV1aVf/epXmjBhgmpra7V+/XrV1dVlrA/f/va3ddlllyXXTzrpJC1ZsqTXk8NnnXWWVq1alVIWDAbT0o8+n9mWpEgkoscff1x//OMfZa2VJH344YdqaWlJS6cAAAAAAINLQ0ODnnnmGd14442aP3++xo4dq5NPPlnLly/Xl770JUnSe++9p3POOUf5+fkqLCzUP/7jP6q2tvaQbW7atElnnHGGysvLVVRUpNNOO02vvPJKSh1jjO6++2596UtfUl5enm655RZVVlYmX67rqqCgIKUsIXH2veerpKQkLT+PPoftv/3tb5o5c6bOOeccLV26VHv37pUk3XjjjfrOd76Tlk4BAAAAAAaX/Px85efna82aNers7Dxou+d5Ouecc1RfX6+nnnpK69at0zvvvKPzzjvvkG02Nzfroosu0rPPPqsXXnhBkyZN0tlnn63m5uaUetdff72+/OUva8uWLfrGN76R9u92JPoctq+66irNmTNH+/fvV05OTrL8y1/+stavX5/WzgEAAAAABgefz6f77rtPv/rVr1RcXKxTTjlF1157rV577TVJsYm1t2zZot/97nc68cQTNXfuXP3617/WU089pU2b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6u///u/1b//2b3r99dc1ffp0ffOb39TXvvY1tbe365prrlEkEtGGDRskSatXr5YxRrNmzVJLS4uuu+467dy5U5s3b5bjONq5c6fGjx+vcePG6ZZbbtHxxx+vUCikUaNGZfnbAgCAj0PYBgAgDfbs2aPp06ervr5eq1ev1tatW/XMM8/oscceS9bZtWuXqqurtX37dn3iE584qI19+/ZpxIgR2rJli2bMmJEM27fddpuuuuqqTH4dAABwlLiMHACANBg5cqT+6Z/+SVOnTtWiRYv06quv6oknnlB+fn7yNWXKFElKXir+1ltvafHixZowYYIKCws1btw4SdJ7772X0vacOXMy+l0AAMDR82W7AwAADBU+n08+X+x/rS0tLfriF7+oG2+88aB6icvAv/jFL2rs2LG65557VFVVJc/zNGPGDHV1daXUz8vL6//OAwCAtCJsAwDQD0444QStXr1a48aNSwbwnurq6rR9+3bdc889+vSnPy1JevbZZzPdTQAA0E+4jBwAgH6wdOlS1dfXa/Hixdq0aZN27Nihxx57TBdffLGi0ahKSkpUVlamn//853r77be1YcMGLVu2LNvdBgAAaULYBgCgH1RVVem5555TNBrVmWeeqZkzZ+rqq69WcXGxHMeR4zi6//779fLLL2vGjBn6l3/5F918883Z7jYAAEgTZiMHAAAAACDNOLMNAAAAAECaEbYBAAAAAEgzwjYAAAAAAGlG2AYAAAAAIM0I2wAAAAAApBlhGwAAAACANCNsAwAAAACQZoRtAAAAAADSjLANAAAAAECaEbYBAAAAAEgzwjYAAAAAAGn2/wHfNGWqd4n61gAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Make an area chart with the data considering each as a portion of the whole\n", + "plt.figure(figsize=(10, 5))\n", + "plt.stackplot(years, Nuclear_TEELECE, Hydro_TEELECE, Coal_TEELECE, Gas_TEELECE, Bioele_TEELECE, Sldwast_TEELECE, SolarPV_TEELECE, Wind_TEELECE, SolarTE_TEELECE, labels=['Nuclear', 'Hydro', 'Coal', 'Gas', 'Bioele', 'Sldwast', 'SolarPV', 'Wind', 'SolarTE'])\n", + "plt.legend(loc='upper left')\n", + "# put the leged out of the plot\n", + "plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))\n", + "plt.title('Electricity Generation Mix for TEELECE')\n", + "plt.xlabel('Year')\n", + "plt.ylabel('Electricity Generation (GWh)')\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "y2020_sTEELE_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEELE')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2025_sTEELE_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEELE')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2030_sTEELE_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEELE')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2035_sTEELE_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEELE')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2040_sTEELE_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEELE')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2045_sTEELE_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEELE')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2050_sTEELE_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEELE')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEOPDIE_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2025_sTEOPDIE_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2030_sTEOPDIE_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2035_sTEOPDIE_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2040_sTEOPDIE_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2045_sTEOPDIE_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2050_sTEOPDIE_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEOLPG_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPLPG')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2025_sTEOLPG_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPLPG')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2030_sTEOLPG_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPLPG')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2035_sTEOLPG_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPLPG')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2040_sTEOLPG_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPLPG')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2045_sTEOLPG_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPLPG')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2050_sTEOLPG_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPLPG')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEBIOETH_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIOETH')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2025_sTEBIOETH_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIOETH')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2030_sTEBIOETH_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIOETH')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2035_sTEBIOETH_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIOETH')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2040_sTEBIOETH_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIOETH')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2045_sTEBIOETH_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIOETH')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2050_sTEBIOETH_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIOETH')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEBIODIE_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIODIE')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2025_sTEBIODIE_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIODIE')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2030_sTEBIODIE_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIODIE')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2035_sTEBIODIE_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIODIE')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2040_sTEBIODIE_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIODIE')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2045_sTEBIODIE_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIODIE')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2050_sTEBIODIE_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIODIE')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEOPGSN_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPGSN')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2025_sTEOPGSN_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPGSN')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2030_sTEOPGSN_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPGSN')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2035_sTEOPGSN_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPGSN')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2040_sTEOPGSN_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPGSN')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2045_sTEOPGSN_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPGSN')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2050_sTEOPGSN_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPGSN')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEOPKER_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPKER')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2025_sTEOPKER_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPKER')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2030_sTEOPKER_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPKER')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2035_sTEOPKER_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPKER')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2040_sTEOPKER_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPKER')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2045_sTEOPKER_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPKER')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2050_sTEOPKER_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPKER')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEOPFOI_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPFOI')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2025_sTEOPFOI_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPFOI')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2030_sTEOPFOI_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPFOI')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2035_sTEOPFOI_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPFOI')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2040_sTEOPFOI_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPFOI')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2045_sTEOPFOI_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPFOI')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2050_sTEOPFOI_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPFOI')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTENAGAS_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2025_sTENAGAS_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2030_sTENAGAS_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2035_sTENAGAS_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2040_sTENAGAS_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2045_sTENAGAS_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2050_sTENAGAS_TRA = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "\n", + "\n", + "# Graph bar stackplot\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "sTEELE_TRA = [y2020_sTEELE_TRA, y2025_sTEELE_TRA, y2030_sTEELE_TRA, y2035_sTEELE_TRA, y2040_sTEELE_TRA, y2045_sTEELE_TRA, y2050_sTEELE_TRA]\n", + "sTEOPDIE_TRA = [y2020_sTEOPDIE_TRA, y2025_sTEOPDIE_TRA, y2030_sTEOPDIE_TRA, y2035_sTEOPDIE_TRA, y2040_sTEOPDIE_TRA, y2045_sTEOPDIE_TRA, y2050_sTEOPDIE_TRA]\n", + "sTEOLPG_TRA = [y2020_sTEOLPG_TRA, y2025_sTEOLPG_TRA, y2030_sTEOLPG_TRA, y2035_sTEOLPG_TRA, y2040_sTEOLPG_TRA, y2045_sTEOLPG_TRA, y2050_sTEOLPG_TRA]\n", + "sTEBIOETH_TRA = [y2020_sTEBIOETH_TRA, y2025_sTEBIOETH_TRA, y2030_sTEBIOETH_TRA, y2035_sTEBIOETH_TRA, y2040_sTEBIOETH_TRA, y2045_sTEBIOETH_TRA, y2050_sTEBIOETH_TRA]\n", + "sTEBIODIE_TRA = [y2020_sTEBIODIE_TRA, y2025_sTEBIODIE_TRA, y2030_sTEBIODIE_TRA, y2035_sTEBIODIE_TRA, y2040_sTEBIODIE_TRA, y2045_sTEBIODIE_TRA, y2050_sTEBIODIE_TRA]\n", + "sTEOPGSN_TRA = [y2020_sTEOPGSN_TRA, y2025_sTEOPGSN_TRA, y2030_sTEOPGSN_TRA, y2035_sTEOPGSN_TRA, y2040_sTEOPGSN_TRA, y2045_sTEOPGSN_TRA, y2050_sTEOPGSN_TRA]\n", + "sTEOPKER_TRA = [y2020_sTEOPKER_TRA, y2025_sTEOPKER_TRA, y2030_sTEOPKER_TRA, y2035_sTEOPKER_TRA, y2040_sTEOPKER_TRA, y2045_sTEOPKER_TRA, y2050_sTEOPKER_TRA]\n", + "sTEOPFOI_TRA = [y2020_sTEOPFOI_TRA, y2025_sTEOPFOI_TRA, y2030_sTEOPFOI_TRA, y2035_sTEOPFOI_TRA, y2040_sTEOPFOI_TRA, y2045_sTEOPFOI_TRA, y2050_sTEOPFOI_TRA]\n", + "sTENAGAS_TRA = [y2020_sTENAGAS_TRA, y2025_sTENAGAS_TRA, y2030_sTENAGAS_TRA, y2035_sTENAGAS_TRA, y2040_sTENAGAS_TRA, y2045_sTENAGAS_TRA, y2050_sTENAGAS_TRA]\n", + "\n", + "\n", + "plt.bar(years, sTEELE_TRA, label='Electricity', color='blue')\n", + "plt.bar(years, sTEOPDIE_TRA, label='Diesel', color='red', bottom=sTEELE_TRA)\n", + "plt.bar(years, sTEOLPG_TRA, label='LPG', color='green', bottom=[sum(x) for x in zip(sTEELE_TRA, sTEOPDIE_TRA)])\n", + "plt.bar(years, sTEBIOETH_TRA, label='Bioethanol', color='orange', bottom=[sum(x) for x in zip(sTEELE_TRA, sTEOPDIE_TRA, sTEOLPG_TRA)])\n", + "plt.bar(years, sTEBIODIE_TRA, label='Biodiesel', color='brown', bottom=[sum(x) for x in zip(sTEELE_TRA, sTEOPDIE_TRA, sTEOLPG_TRA, sTEBIOETH_TRA)])\n", + "plt.bar(years, sTEOPGSN_TRA, label='Gasoline', color='purple', bottom=[sum(x) for x in zip(sTEELE_TRA, sTEOPDIE_TRA, sTEOLPG_TRA, sTEBIOETH_TRA, sTEBIODIE_TRA)])\n", + "plt.bar(years, sTEOPKER_TRA, label='Kerosene', color='yellow', bottom=[sum(x) for x in zip(sTEELE_TRA, sTEOPDIE_TRA, sTEOLPG_TRA, sTEBIOETH_TRA, sTEBIODIE_TRA, sTEOPGSN_TRA)])\n", + "plt.bar(years, sTEOPFOI_TRA, label='Fuel Oil', color='pink', bottom=[sum(x) for x in zip(sTEELE_TRA, sTEOPDIE_TRA, sTEOLPG_TRA, sTEBIOETH_TRA, sTEBIODIE_TRA, sTEOPGSN_TRA, sTEOPKER_TRA)])\n", + "plt.bar(years, sTENAGAS_TRA, label='Natural Gas', color='grey', bottom=[sum(x) for x in zip(sTEELE_TRA, sTEOPDIE_TRA, sTEOLPG_TRA, sTEBIOETH_TRA, sTEBIODIE_TRA, sTEOPGSN_TRA, sTEOPKER_TRA, sTEOPFOI_TRA)])\n", + "\n", + "plt.title('TE consumed by ST in TRA sector')\n", + "plt.xlabel('Year')\n", + "plt.ylabel('[GWh]')\n", + "plt.legend()\n", + "plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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WVru379f1iERERERUTlQ5nfCNTU1YWdnBwBwcXHB+fPnsWrVKvTr1w8ZGRlISkpSugP94MEDmJubAwDMzc3zzWKSN2PJy21encXkwYMHkMvl0NHRgbq6OtTV1Qts83Ifb4ulIFpaWtDS0ipCNoiIiIioMijzO+GvysnJQXp6OlxcXKChoYGQkBBpW1RUFOLi4uDq6goAcHV1xdWrV5GYmCi1OXr0KORyOerWrSu1ebmPvDZ5fWhqasLFxUWpTU5ODkJCQqQ2hYmFiIiIiKiwyvRO+PTp09G5c2dYW1vj6dOn2LZtG0JDQ3H48GEYGhpi+PDh8PX1hZGREeRyOcaNGwdXV1fpQchOnTqhbt26GDRoEJYuXYqEhATMmjUL3t7e0h3ozz77DN9++y2mTJmCYcOG4dixY9i5cycOHjwoxeHr64shQ4agadOmaN68OVauXIlnz55h6NChAFCoWIiIiIiICqtMi/DExEQMHjwY8fHxMDQ0RMOGDXH48GF07NgRALBixQqoqamhT58+SE9Ph4eHB9atWyftr66ujgMHDmDMmDFwdXWFnp4ehgwZgvnz50ttbG1tcfDgQUyaNAmrVq1CjRo1sGnTJmmOcADo168fHj58iNmzZyMhIQGNGzdGcHCw0sOab4uFiIiIiKiwyvRlPZVNSkoKDA0NkZyczNlRiIiI3hP8+U2lodyNCSciIiIiquhYhBMRERERqRiLcCIiIiIiFWMRTkRERESkYizCiYiIiIhUjEU4EREREZGKsQgnIiIiIlIxFuFERERERCrGIpyIiIiISMXK9LX1REREqiaTyco6hBLHl18TvX9YhBMREVVC/GWEqGxxOAoRERERkYqxCCciIiIiUjEW4UREREREKsYinIiIiIhIxViEExERERGpGItwIiIiIiIVYxFORERERKRiLMKJiIiIiFSMRTgRERERkYqxCCciIiIiUjG+tp6IqJLga8qJiMoP3gknIiIiIlIxFuFERERERCrGIpyIiIiISMVYhBMRERERqRiLcCIiIiIiFWMRTkRERESkYizCiYiIiIhUjEU4EREREZGKsQgnIiIiIlIxFuFERERERCrGIpyIiIiISMVYhBMRERERqRiLcCIiIiIiFWMRTkRERESkYizCiYiIiIhUjEU4EREREZGKsQgnIiIiIlKxKmUdABERkSrNnTu3rEMgIoJM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aNAg/Pvvv9K+wcHB+OCDD6BQKGBsbIxu3bohOjpa2h4bGwuZTIYdO3agXbt20NbWxtatW8viNImIqAzJhBCirIMgIiqPevbsieTkZPTu3RsLFizA9evXUa9ePYwYMQKDBw9GWloapk6diqysLBw7dgwA8Msvv0Amk6Fhw4ZITU3F7NmzERsbi4iICKipqSE2Nha2trawsbHB8uXL4ezsDG1tbVhYWJTx2RIRkSqxCCcieo3ExETUq1cPjx8/xi+//IJr167hjz/+wOHDh6U2f/31F6ysrBAVFYU6derk6+Pff/+Fqakprl69ivr160tF+MqVKzFhwgRVng4REZUjHI5CRPQaZmZmGD16NJycnNCzZ09cvnwZx48fh76+vrQ4OjoCgDTk5Pbt2+jfvz9q1aoFuVwOGxsbAEBcXJxS302bNlXpuRARUflSpawDICIqz6pUqYIqVXL/q0xNTUX37t2xZMmSfO3yhpN0794dNWvWxMaNG2FpaYmcnBzUr18fGRkZSu319PRKP3giIiq3WIQTERVSkyZN8Msvv8DGxkYqzF/26NEjREVFYePGjWjTpg0A4NSpU6oOk4iI3gMcjkJEVEje3t54/Pgx+vfvj/PnzyM6OhqHDx/G0KFDkZ2djapVq8LY2BgbNmzAnTt3cOzYMfj6+pZ12EREVA6xCCciKiRLS0ucPn0a2dnZ6NSpExo0aICJEydCoVBATU0Nampq2L59O8LDw1G/fn1MmjQJy5YtK+uwiYioHOLsKEREREREKsY74UREREREKsYinIiIiIhIxViEExERERGpGItwIiIiIiIVYxFORERERKRiLMKJiIiIiFSMRTgRERERkYqxCCciIiIiUjEW4UREREREKsYinIiIiIhIxViEExERERGpGItwIiIiIiIV+z+KNi3G54mOhAAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "y2020_sTEELE_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEELEIND')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2025_sTEELE_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEELEIND')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2030_sTEELE_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEELEIND')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2035_sTEELE_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEELEIND')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2040_sTEELE_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEELEIND')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2045_sTEELE_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEELEIND')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2050_sTEELE_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEELEIND')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEOPDIE_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2025_sTEOPDIE_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2030_sTEOPDIE_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2035_sTEOPDIE_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2040_sTEOPDIE_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2045_sTEOPDIE_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2050_sTEOPDIE_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEOPFOI_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPFOI')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2025_sTEOPFOI_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPFOI')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2030_sTEOPFOI_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPFOI')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2035_sTEOPFOI_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPFOI')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2040_sTEOPFOI_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPFOI')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2045_sTEOPFOI_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPFOI')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2050_sTEOPFOI_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPFOI')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEOPLPG_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPLPG')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2025_sTEOPLPG_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPLPG')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2030_sTEOPLPG_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPLPG')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2035_sTEOPLPG_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPLPG')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2040_sTEOPLPG_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPLPG')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2045_sTEOPLPG_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPLPG')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2050_sTEOPLPG_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPLPG')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTENAGAS_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2025_sTENAGAS_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2030_sTENAGAS_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2035_sTENAGAS_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2040_sTENAGAS_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2045_sTENAGAS_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2050_sTENAGAS_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTECOAL_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTECOAL')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2025_sTECOAL_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTECOAL')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2030_sTECOAL_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTECOAL')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2035_sTECOAL_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTECOAL')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2040_sTECOAL_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTECOAL')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2045_sTECOAL_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTECOAL')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2050_sTECOAL_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTECOAL')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEH2_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEH2')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2025_sTEH2_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEH2')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2030_sTEH2_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEH2')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2035_sTEH2_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEH2')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2040_sTEH2_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEH2')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2045_sTEH2_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEH2')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2050_sTEH2_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEH2')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEOPKER_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPKER')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2025_sTEOPKER_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPKER')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2030_sTEOPKER_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPKER')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2035_sTEOPKER_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPKER')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2040_sTEOPKER_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPKER')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2045_sTEOPKER_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPKER')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2050_sTEOPKER_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEOPKER')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEBIODIE_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIODIE')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2025_sTEBIODIE_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIODIE')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2030_sTEBIODIE_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIODIE')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2035_sTEBIODIE_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIODIE')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2040_sTEBIODIE_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIODIE')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2045_sTEBIODIE_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIODIE')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2050_sTEBIODIE_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIODIE')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEBIOMA_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIOMA')) & (data_results['vQSTInTE'].sYear=='y2020') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2025_sTEBIOMA_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIOMA')) & (data_results['vQSTInTE'].sYear=='y2025') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2030_sTEBIOMA_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIOMA')) & (data_results['vQSTInTE'].sYear=='y2030') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2035_sTEBIOMA_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIOMA')) & (data_results['vQSTInTE'].sYear=='y2035') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2040_sTEBIOMA_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIOMA')) & (data_results['vQSTInTE'].sYear=='y2040') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2045_sTEBIOMA_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIOMA')) & (data_results['vQSTInTE'].sYear=='y2045') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "y2050_sTEBIOMA_IND = data_results['vQSTInTE'][(data_results['vQSTInTE'].sTE.str.startswith('sTEBIOMA')) & (data_results['vQSTInTE'].sYear=='y2050') & (data_results['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "sTEELE_IND = [y2020_sTEELE_IND, y2025_sTEELE_IND, y2030_sTEELE_IND, y2035_sTEELE_IND, y2040_sTEELE_IND, y2045_sTEELE_IND, y2050_sTEELE_IND]\n", + "sTEOPDIE_IND = [y2020_sTEOPDIE_IND, y2025_sTEOPDIE_IND, y2030_sTEOPDIE_IND, y2035_sTEOPDIE_IND, y2040_sTEOPDIE_IND, y2045_sTEOPDIE_IND, y2050_sTEOPDIE_IND]\n", + "sTEOPFOI_IND = [y2020_sTEOPFOI_IND, y2025_sTEOPFOI_IND, y2030_sTEOPFOI_IND, y2035_sTEOPFOI_IND, y2040_sTEOPFOI_IND, y2045_sTEOPFOI_IND, y2050_sTEOPFOI_IND]\n", + "sTEOPLPG_IND = [y2020_sTEOPLPG_IND, y2025_sTEOPLPG_IND, y2030_sTEOPLPG_IND, y2035_sTEOPLPG_IND, y2040_sTEOPLPG_IND, y2045_sTEOPLPG_IND, y2050_sTEOPLPG_IND]\n", + "sTENAGAS_IND = [y2020_sTENAGAS_IND, y2025_sTENAGAS_IND, y2030_sTENAGAS_IND, y2035_sTENAGAS_IND, y2040_sTENAGAS_IND, y2045_sTENAGAS_IND, y2050_sTENAGAS_IND]\n", + "sTECOAL_IND = [y2020_sTECOAL_IND, y2025_sTECOAL_IND, y2030_sTECOAL_IND, y2035_sTECOAL_IND, y2040_sTECOAL_IND, y2045_sTECOAL_IND, y2050_sTECOAL_IND]\n", + "sTEH2_IND = [y2020_sTEH2_IND, y2025_sTEH2_IND, y2030_sTEH2_IND, y2035_sTEH2_IND, y2040_sTEH2_IND, y2045_sTEH2_IND, y2050_sTEH2_IND]\n", + "sTEOPKER_IND = [y2020_sTEOPKER_IND, y2025_sTEOPKER_IND, y2030_sTEOPKER_IND, y2035_sTEOPKER_IND, y2040_sTEOPKER_IND, y2045_sTEOPKER_IND, y2050_sTEOPKER_IND]\n", + "sTEBIODIE_IND = [y2020_sTEBIODIE_IND, y2025_sTEBIODIE_IND, y2030_sTEBIODIE_IND, y2035_sTEBIODIE_IND, y2040_sTEBIODIE_IND, y2045_sTEBIODIE_IND, y2050_sTEBIODIE_IND]\n", + "sTEBIOMA_IND = [y2020_sTEBIOMA_IND, y2025_sTEBIOMA_IND, y2030_sTEBIOMA_IND, y2035_sTEBIOMA_IND, y2040_sTEBIOMA_IND, y2045_sTEBIOMA_IND, y2050_sTEBIOMA_IND]\n", + "\n", + "plt.bar(years, sTEELE_IND, label='Electricity', color='blue')\n", + "plt.bar(years, sTEOPDIE_IND, label='Diesel', color='red', bottom=sTEELE_IND)\n", + "plt.bar(years, sTEOPFOI_IND, label='Fuel Oil', color='green', bottom=[sum(x) for x in zip(sTEELE_IND, sTEOPDIE_IND)])\n", + "plt.bar(years, sTEOPLPG_IND, label='LPG', color='orange', bottom=[sum(x) for x in zip(sTEELE_IND, sTEOPDIE_IND, sTEOPFOI_IND)])\n", + "plt.bar(years, sTENAGAS_IND, label='Natural Gas', color='brown', bottom=[sum(x) for x in zip(sTEELE_IND, sTEOPDIE_IND, sTEOPFOI_IND, sTEOPLPG_IND)])\n", + "plt.bar(years, sTECOAL_IND, label='Coal', color='purple', bottom=[sum(x) for x in zip(sTEELE_IND, sTEOPDIE_IND, sTEOPFOI_IND, sTEOPLPG_IND, sTENAGAS_IND)])\n", + "plt.bar(years, sTEH2_IND, label='Hydrogen', color='yellow', bottom=[sum(x) for x in zip(sTEELE_IND, sTEOPDIE_IND, sTEOPFOI_IND, sTEOPLPG_IND, sTENAGAS_IND, sTECOAL_IND)])\n", + "plt.bar(years, sTEOPKER_IND, label='Kerosene', color='pink', bottom=[sum(x) for x in zip(sTEELE_IND, sTEOPDIE_IND, sTEOPFOI_IND, sTEOPLPG_IND, sTENAGAS_IND, sTECOAL_IND, sTEH2_IND)])\n", + "plt.bar(years, sTEBIODIE_IND, label='Biodiesel', color='grey', bottom=[sum(x) for x in zip(sTEELE_IND, sTEOPDIE_IND, sTEOPFOI_IND, sTEOPLPG_IND, sTENAGAS_IND, sTECOAL_IND, sTEH2_IND, sTEOPKER_IND)])\n", + "plt.bar(years, sTEBIOMA_IND, label='Biomass', color='black', bottom=[sum(x) for x in zip(sTEELE_IND, sTEOPDIE_IND, sTEOPFOI_IND, sTEOPLPG_IND, sTENAGAS_IND, sTECOAL_IND, sTEH2_IND, sTEOPKER_IND, sTEBIODIE_IND)])\n", + "\n", + "plt.title('TE consumed by ST in IND sector')\n", + "plt.xlabel('Year')\n", + "plt.ylabel('[GWh]')\n", + "plt.legend()\n", + "plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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v39/ju379+/XgQMHnFETAAAA4BIOh+N+/frpu+++y7F927Zt6tevnzNqAgAAAFzC4XD8008/qXnz5jm233PPPdq5c6czagIAAABcwuFwbLFYdObMmRzb09PTlZWV5ZSiAAAAAFdwOBy3bNlS48aNswvCWVlZGjdunFq0aOHU4gAAAIDC5PBLQP7973+rZcuWql27tu677z5J0qZNm5SRkaF169Y5vUAAAACgsDh857hevXratWuXHn30UR07dkxnzpxRnz59tG/fPkVERBREjQAAAEChyNfro0NDQ/Xmm286uxYAAADApfIUjnft2qWIiAh5eHho165dN20bGRnplMIAAACAwpancNyoUSOlpaUpMDBQjRo1ksVikWEYOdpZLBaeWAEAAIBiK0/hOCUlRZUrV7b9DAAAUBRkZWXp8uXLri4DRZynp6c8PPL2Vbs8hePw8PBcfwYAAHAFwzCUlpam06dPu7oUFAMeHh6qXr26PD09/7Jtvr6Qt3//fq1fv17Hjh1Tdna23b7XXnstP10CAADk2bVgHBgYKG9vb1ksFleXhCIqOztbR44cUWpqqqpWrfqX14rD4Xj69OkaNGiQAgICFBwcbHcAi8VCOAYAAAUqKyvLFowrVark6nJQDFSuXFlHjhzRlStXVKZMmZu2dTgcv/HGGxo7dqxeeumlfBcIAACQX9fmGHt7e7u4EhQX16ZTZGVl/WU4dvglIKdOndIjjzySv8oAAACchKkUyCtHrhWHw/Ejjzyib775xtGPAQAAAEVenqZVTJ482fZzzZo19a9//Utbt25VgwYNctyaHjp0qHMrBAAAQLHRunVrNWrUSBMnTizU41osFi1evFjdunW7pX7yFI4nTJhgt+7j46OEhAQlJCTkKIpwDAAAXKGwZ1nk8j60PElLS9PYsWO1YsUK/fe//7W9ZG3YsGFq27atc4ssQBs2bFCbNm106tQp+fv727YvWrToL+f1FmV5fgkIAAAAbs2BAwfUvHlz+fv76+2331aDBg10+fJlrVq1StHR0dq3b5+rS7xlFStWdHUJt8ThOcfXXLp0SYmJibpy5Yoz6wEAAHBbgwcPlsVi0ffff68ePXrojjvuUP369RUTE6OtW7dKkg4ePKiuXbvKx8dHvr6+evTRR3X06FFbH6NGjVKjRo00d+5cVatWTX5+fnrsscd05swZSdKHH36o0NDQHO+i6Nq1q/r3729b//LLL9W4cWN5eXmpRo0aGj16tF2us1gsmjFjhh5++GF5e3urVq1aWrp0qaSrIb9NmzaSpAoVKshisahfv36Srk6rGDZsmK2fU6dOqU+fPqpQoYK8vb3VqVMn7d+/37Z/9uzZ8vf316pVq1S3bl35+PjogQceUGpqqq3N9u3b1b59ewUEBMjPz0+tWrXSjz/+eCv/KW7I4XB8/vx5PfXUU/L29lb9+vV18OBBSdI//vEPjR8/3ukFAgAAuIOTJ09q5cqVio6OVrly5XLs9/f3V3Z2trp27aqTJ08qISFBq1ev1u+//66ePXvatU1OTtaSJUu0fPlyLV++XAkJCbYc9sgjj+jEiRNav359jmM//vjjkqRNmzapT58+eu6557R3715NmzZNs2fP1tixY+2OM3r0aD366KPatWuXOnfurMcff1wnT55UWFiYFi5cKElKTExUamqqJk2alOt59+vXTz/88IOWLl2qLVu2yDAMde7c2e613+fPn9f/+3//T3PnztXGjRt18OBBvfDCC7b9Z86cUd++fbV582Zt3bpVtWrVUufOnW3/Q+BMDofj2NhY/fzzz9qwYYO8vLxs29u1a6cFCxY4tTgAAAB3kZSUJMMwVKdOnRu2Wbt2rXbv3q358+erSZMmatasmT766CMlJCRo+/bttnbZ2dmaPXu2IiIidN999+mJJ57Q2rVrJV29k9upUyfNnz/f1v6LL75QQECA7W7v6NGj9fLLL6tv376qUaOG2rdvr9dff13Tpk2zq6dfv37q1auXatasqTfffFNnz57V999/r1KlStmmTwQGBio4OFh+fn45zmf//v1aunSpZsyYofvuu08NGzbUvHnz9N///ldLliyxtbt8+bKmTp2qpk2bqnHjxhoyZIjtfCTp/vvvV+/evVWnTh3VrVtXH374oc6fP5/j+2/O4HA4XrJkid5//321aNHC7plx9evXV3JyslOLAwAAcBdGHr7B9+uvvyosLExhYWG2bfXq1ZO/v79+/fVX27Zq1aqpfPnytvWQkBAdO3bMtv74449r4cKFyszMlCTNmzdPjz32mDw8rka/n3/+WWPGjJGPj49tGTBggFJTU3X+/HlbP5GRkbafy5UrJ19fX7vj5OV8SpcurWbNmtm2VapUSbVr17Y7H29vb91+++03PJ+jR49qwIABqlWrlvz8/OTr66uzZ8/aZjA4k8NvyPvf//6nwMDAHNvPnTvHw7gBAABuoFatWrJYLE750t2fnwZhsVjs5hh36dJFhmFoxYoVuuuuu7Rp0ya7p4+dPXtWo0ePVvfu3XP0ff3MgL86jrPkdpzr/2eib9++OnHihCZNmqTw8HBZrVZFRUXp0qVLTq/F4TvHTZs21YoVK2zr1wLxjBkzFBUV5bzKAAAA3EjFihXVsWNHTZkyRefOncux//Tp06pbt64OHTqkQ4cO2bbv3btXp0+fVr169fJ8LC8vL3Xv3l3z5s3TJ598otq1a6tx48a2/Y0bN1ZiYqJq1qyZY7l2d/mvXP9K5hupW7eurly5om3bttm2nThxQomJiQ6dz7fffquhQ4eqc+fOql+/vqxWq44fP57nzzvC4TvHb775pjp16qS9e/fqypUrmjRpkvbu3avvvvuuQOZ9AAAAuIspU6aoefPmuvvuuzVmzBhFRkbqypUrWr16teLi4rR37141aNBAjz/+uCZOnKgrV65o8ODBatWqlZo2berQsR5//HE9+OCD+uWXX9S7d2+7fa+99poefPBBVa1aVX/729/k4eGhn3/+WXv27NEbb7yRp/7Dw8NlsVi0fPlyde7cWWXLlpWPj49dm1q1aqlr164aMGCApk2bpvLly+vll1/Wbbfdpq5du+b5XGrVqqW5c+eqadOmysjI0IsvvqiyZcvm+fOOcPjOcYsWLbRz505duXJFDRo00DfffKPAwEBt2bJFTZo0KYgaAQAA3EKNGjX0448/qk2bNnr++ecVERGh9u3ba+3atYqLi5PFYtGXX36pChUqqGXLlmrXrp1q1KiRr4ce3H///apYsaISExP197//3W5fx44dtXz5cn3zzTe66667dM8992jChAkKDw/Pc/+33Xab7Yt9QUFBGjJkSK7t4uPj1aRJEz344IOKioqSYRj66quvHHpRyMyZM3Xq1Ck1btxYTzzxhIYOHZrrNF9nsBh5mR1ejGVkZMjPz0/p6eny9fV1at/uOMU6v1cDY3EV43CVZbT7DYQxMn9/OBiLqxiHqxiHvLvZ7++LFy8qJSVF1atXt5sfC9yII9eMw3eO27Vrp9mzZysjIyPfBQIAAABFkcPhuH79+oqNjVVwcLAeeeQRffnll3YPcXbEuHHjdNddd6l8+fIKDAxUt27dlJiYaNfm4sWLio6OVqVKleTj46MePXrYvSUGAAAAcBaHw/GkSZNsD24uV66c+vTpo6CgIA0cONDhL+QlJCQoOjpaW7du1erVq3X58mV16NDB7hucw4cP17Jly/T5558rISFBR44cyfWxIwAAAMCtcvhpFZLk4eGhDh06qEOHDpo6daqWLVumsWPHaubMmTd9nMefrVy50m599uzZCgwM1I4dO9SyZUulp6dr5syZmj9/vu6//35JVyd1161bV1u3btU999yTn/IBAACAXOUrHF+TlpamTz/9VB9//LF27dqlu++++5aKSU9PlyTb6wh37Nihy5cvq127drY2derUUdWqVbVly5Zcw3FmZqbtbTCSmBsNAACAPHN4WkVGRobi4+PVvn17hYWFKS4uTg899JD279+vrVu35ruQ7OxsDRs2TM2bN1dERISkq+Hb09NT/v7+dm2DgoKUlpaWaz/jxo2Tn5+fbbn+9YsAAADAzTh85zgoKEgVKlRQz549NW7cOIcfSH0j0dHR2rNnjzZv3nxL/cTGxiomJsa2npGRQUAGAABAnjgcjpcuXaq2bdvm+dWCeTFkyBAtX75cGzduVJUqVWzbg4ODdenSJZ0+fdru7vHRo0cVHByca19Wq1VWq9VptQEAAKDkcDjhtm/f3mnB2DAMDRkyRIsXL9a6detUvXp1u/1NmjRRmTJltHbtWtu2xMREHTx4UFFRUU6pAQAAALjGebd/8yE6Oloff/yx5s+fr/LlyystLU1paWm6cOGCJMnPz09PPfWUYmJitH79eu3YsUNPPvmkoqKieFIFAAAokQ4cOCCLxaKdO3c6/NlRo0apUaNGN23Tr18/devWLV+1uQOXhuO4uDilp6erdevWCgkJsS3Xvz98woQJevDBB9WjRw+1bNlSwcHBWrRokQurBgAARZLFUrhLPtwoeG7YsEEWi0WnT5++tTH4Cy+88ILdv8gjp1t6lNutMoy/fh+7l5eXpkyZoilTphRCRQAAAO7HMAxlZWXJx8dHPj4+ri6nSMvTneOKFSvq+PHjkqT+/fvrzJkzBVoUAABASXTu3Dn5+vrqiy++sNt+7c3E12ewffv26d5775WXl5ciIiLs3lR87U70119/rSZNmshqtWrz5s05plVkZWUpJiZG/v7+qlSpkkaMGJGnm5fuLE/h+NKlS7aXacyZM0cXL14s0KIAAABKonLlyumxxx5TfHy83fb4+Hj97W9/U/ny5W3bXnzxRT3//PP66aefFBUVpS5duujEiRN2n3v55Zc1fvx4/frrr4qMjMxxvHfeeUezZ8/WrFmztHnzZp08eVKLFy8umJMrJvI0rSIqKkrdunVTkyZNZBiGhg4dqrJly+badtasWU4tEAAAwJ0sX748x9SGrKws289PP/207r33XqWmpiokJETHjh3TV199pTVr1th9ZsiQIerRo4ekq9/jWrlypWbOnKkRI0bY2owZM0bt27e/YS0TJ05UbGysunfvLkmaOnWqVq1adcvnWJzl6c7xxx9/rM6dO+vs2bOyWCxKT0/XqVOncl0AAABwY23atNHOnTvtlhkzZtj233333apfv77mzJkj6WoOCw8PV8uWLe36uf6xtqVLl1bTpk3166+/2rW52cva0tPTlZqaqmbNmuXopyTL053joKAgjR8/XpJUvXp1zZ07V5UqVSrQwgAUX8YoV1dQAEa6ugAA7qJcuXKqWbOm3bbDhw/brT/99NOaMmWKXn75ZcXHx+vJJ5+UJR9PyChXrtwt1VoSOfwot5SUFIIxAABAAerdu7f+85//aPLkydq7d6/69u2bo83WrVttP1+5ckU7duxQ3bp183wMPz8/hYSEaNu2bTn6Kcny9ZzjhIQEdenSRTVr1lTNmjX10EMPadOmTc6uDQAAoESqUKGCunfvrhdffFEdOnRQlSpVcrSZMmWKFi9erH379ik6OlqnTp1S//79HTrOc889p/Hjx2vJkiXat2+fBg8eXODPWi7qHA7HH3/8sdq1aydvb28NHTrU9uW8tm3bav78+QVRIwAAQInz1FNP6dKlSzcMvOPHj9f48ePVsGFDbd68WUuXLlVAQIBDx3j++ef1xBNPqG/fvoqKilL58uX18MMPO6P8YstiOPgwu7p162rgwIEaPny43fZ3331X06dPzzER3NUyMjLk5+en9PR0+fr6OrXvfL4cp0jL76MNGYurGAcTA2FjGe1+Y2GMdHwsGIerGIe8u9nv74sXLyolJUXVq1eXl5dXgRy/KJg7d66GDx+uI0eOyNPT09XlFGuOXDMO3zn+/fff1aVLlxzbH3roIaWkpDjaHQAAAK5z/vx5JScna/z48XrmmWcIxoXM4XAcFhaW6zu516xZo7CwMKcUBQAAUFK99dZbqlOnjoKDgxUbG+vqckqcPD3K7XrPP/+8hg4dqp07d+ree++VJH377beaPXu2Jk2a5PQCAQAASpJRo0Zp1KhRri6jxHI4HA8aNEjBwcF655139Nlnn0m6Og95wYIF6tq1q9MLBAAAAAqLw+FYkh5++OES/01GAAAAuJ98PecYAAAAcEeEYwAAAMBEOAYAAABMhGMAAADAdMvhOCsrSzt37tSpU6ecUQ8AAECJZbFYtGTJEpccu3Xr1ho2bJhLjl2UOPy0imHDhqlBgwZ66qmnlJWVpVatWum7776Tt7e3li9frtatWxdAmQAAADdX2K/nzs+rs/v166c5c+bk2N6xY0etXLnSGWXZsVgsWrx4sbp16/aXbRctWqQyZco4vYbixuFw/MUXX6h3796SpGXLliklJUX79u3T3Llz9c9//lPffvut04sEAABwFw888IDi4+PttlmtVhdVI126dEmenp6qWLGiy2ooShyeVnH8+HEFBwdLkr766is98sgjuuOOO9S/f3/t3r3b6QUCAAC4E6vVquDgYLulQoUKubY9dOiQHn30Ufn7+6tixYrq2rWrDhw4YNdm1qxZql+/vqxWq0JCQjRkyBBJUrVq1SRdfT+FxWKxrY8aNUqNGjXSjBkzVL16dXl5eUnKOa0iMzNTL730ksLCwmS1WlWzZk3NnDnTqWNRFDkcjoOCgrR3715lZWVp5cqVat++vSTp/PnzKlWqlNMLBAAAKIkuX76sjh07qnz58tq0aZO+/fZb+fj46IEHHtClS5ckSXFxcYqOjtbAgQO1e/duLV26VDVr1pQkbd++XZIUHx+v1NRU27okJSUlaeHChVq0aJF27tyZ6/H79OmjTz75RJMnT9avv/6qadOmycfHp2BPughweFrFk08+qUcffVQhISGyWCxq166dJGnbtm2qU6eO0wsEAABwJ8uXL88RMl955RW98sordtsWLFig7OxszZgxQxbL1fnU8fHx8vf314YNG9ShQwe98cYbev755/Xcc8/ZPnfXXXdJkipXrixJ8vf3t/2r/zWXLl3SRx99ZGvzZ7/99ps+++wzrV692pb1atSocQtnXXw4HI5HjRqliIgIHTp0SI888ohtjkypUqX08ssvO71AAAAAd9KmTRvFxcXZbcttvu/PP/+spKQklS9f3m77xYsXlZycrGPHjunIkSNq27atwzWEh4ffMBhL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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "CarGasoline_2020 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2020') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSN'))].vSTTotCap.sum()\n", + "CarDiesel_2020 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2020') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADST'))].vSTTotCap.sum()\n", + "CarCNG_2020 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2020') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CACNG'))].vSTTotCap.sum()\n", + "CarLPG_2020 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2020') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CALPG'))].vSTTotCap.sum()\n", + "CarGasolineHyb_2020 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2020') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSNPIHYB'))].vSTTotCap.sum()\n", + "CarDieselHyb_2020 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2020') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADIEPIHYB'))].vSTTotCap.sum()\n", + "CarElectric_2020 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2020') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CABEV'))].vSTTotCap.sum()\n", + "\n", + "CarGasoline_2025 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2025') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSN'))].vSTTotCap.sum()\n", + "CarDiesel_2025 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2025') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADST'))].vSTTotCap.sum()\n", + "CarCNG_2025 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2025') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CACNG'))].vSTTotCap.sum()\n", + "CarLPG_2025 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2025') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CALPG'))].vSTTotCap.sum()\n", + "CarGasolineHyb_2025 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2025') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSNPIHYB'))].vSTTotCap.sum()\n", + "CarDieselHyb_2025 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2025') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADIEPIHYB'))].vSTTotCap.sum()\n", + "CarElectric_2025 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2025') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CABEV'))].vSTTotCap.sum()\n", + "\n", + "CarGasoline_2030 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2030') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSN'))].vSTTotCap.sum()\n", + "CarDiesel_2030 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2030') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADST'))].vSTTotCap.sum()\n", + "CarCNG_2030 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2030') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CACNG'))].vSTTotCap.sum()\n", + "CarLPG_2030 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2030') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CALPG'))].vSTTotCap.sum()\n", + "CarGasolineHyb_2030 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2030') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSNPIHYB'))].vSTTotCap.sum()\n", + "CarDieselHyb_2030 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2030') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADIEPIHYB'))].vSTTotCap.sum()\n", + "CarElectric_2030 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2030') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CABEV'))].vSTTotCap.sum()\n", + "\n", + "CarGasoline_2035 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2035') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSN'))].vSTTotCap.sum()\n", + "CarDiesel_2035 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2035') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADST'))].vSTTotCap.sum()\n", + "CarCNG_2035 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2035') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CACNG'))].vSTTotCap.sum()\n", + "CarLPG_2035 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2035') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CALPG'))].vSTTotCap.sum()\n", + "CarGasolineHyb_2035 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2035') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSNPIHYB'))].vSTTotCap.sum()\n", + "CarDieselHyb_2035 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2035') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADIEPIHYB'))].vSTTotCap.sum()\n", + "CarElectric_2035 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2035') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CABEV'))].vSTTotCap.sum()\n", + "\n", + "CarGasoline_2040 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2040') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSN'))].vSTTotCap.sum()\n", + "CarDiesel_2040 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2040') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADST'))].vSTTotCap.sum()\n", + "CarCNG_2040 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2040') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CACNG'))].vSTTotCap.sum()\n", + "CarLPG_2040 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2040') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CALPG'))].vSTTotCap.sum()\n", + "CarGasolineHyb_2040 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2040') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSNPIHYB'))].vSTTotCap.sum()\n", + "CarDieselHyb_2040 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2040') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADIEPIHYB'))].vSTTotCap.sum()\n", + "CarElectric_2040 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2040') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CABEV'))].vSTTotCap.sum()\n", + "\n", + "CarGasoline_2045 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2045') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSN'))].vSTTotCap.sum()\n", + "CarDiesel_2045 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2045') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADST'))].vSTTotCap.sum()\n", + "CarCNG_2045 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2045') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CACNG'))].vSTTotCap.sum()\n", + "CarLPG_2045 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2045') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CALPG'))].vSTTotCap.sum()\n", + "CarGasolineHyb_2045 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2045') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSNPIHYB'))].vSTTotCap.sum()\n", + "CarDieselHyb_2045 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2045') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADIEPIHYB'))].vSTTotCap.sum()\n", + "CarElectric_2045 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2045') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CABEV'))].vSTTotCap.sum()\n", + "\n", + "CarGasoline_2050 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2050') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSN'))].vSTTotCap.sum()\n", + "CarDiesel_2050 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2050') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADST'))].vSTTotCap.sum()\n", + "CarCNG_2050 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2050') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CACNG'))].vSTTotCap.sum()\n", + "CarLPG_2050 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2050') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CALPG'))].vSTTotCap.sum()\n", + "CarGasolineHyb_2050 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2050') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSNPIHYB'))].vSTTotCap.sum()\n", + "CarDieselHyb_2050 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2050') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADIEPIHYB'))].vSTTotCap.sum()\n", + "CarElectric_2050 = data_results['vSTTotCap'][(data_results['vSTTotCap'].sYear=='y2050') & (data_results['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CABEV'))].vSTTotCap.sum()\n", + "\n", + "# Graph bar stackplot\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "Car_Conventional = [CarGasoline_2020 + CarDiesel_2020 + CarCNG_2020 + CarLPG_2020, CarGasoline_2025 + CarDiesel_2025 + CarCNG_2025 + CarLPG_2025, CarGasoline_2030 + CarDiesel_2030 + CarCNG_2030 + CarLPG_2030, CarGasoline_2035 + CarDiesel_2035 + CarCNG_2035 + CarLPG_2035, CarGasoline_2040 + CarDiesel_2040 + CarCNG_2040 + CarLPG_2040, CarGasoline_2045 + CarDiesel_2045 + CarCNG_2045 + CarLPG_2045, CarGasoline_2050 + CarDiesel_2050 + CarCNG_2050 + CarLPG_2050]\n", + "Car_Hybrid = [CarGasolineHyb_2020 + CarDieselHyb_2020, CarGasolineHyb_2025 + CarDieselHyb_2025, CarGasolineHyb_2030 + CarDieselHyb_2030, CarGasolineHyb_2035 + CarDieselHyb_2035, CarGasolineHyb_2040 + CarDieselHyb_2040, CarGasolineHyb_2045 + CarDieselHyb_2045, CarGasolineHyb_2050 + CarDieselHyb_2050]\n", + "Car_Electric = [CarElectric_2020, CarElectric_2025, CarElectric_2030, CarElectric_2035, CarElectric_2040, CarElectric_2045, CarElectric_2050]\n", + "\n", + "plt.bar(years, Car_Conventional, label='Conventional', color='blue')\n", + "plt.bar(years, Car_Hybrid, label='Hybrid', color='red', bottom=Car_Conventional)\n", + "plt.bar(years, Car_Electric, label='Electric', color='green', bottom=[sum(x) for x in zip(Car_Conventional, Car_Hybrid)])\n", + "plt.title('Cars')\n", + "plt.xlabel('Year')\n", + "plt.ylabel('Millions of vehicles')\n", + "plt.legend()\n", + "plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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LVoEAPD09MShQ4ewZMkSBAYGGm372ENGRERERETVRlpaGgDAwcEBwMPer9zcXPTs2VMq06xZMzRs2BCJiYmlxtHFAIDExERZDAAIDAwsNYYhsIeMiIiIiBShKjCbhOBMD1QGWq0WU6ZMQefOndGyZUsAQEpKCszNzWFvby8r6+TkhJSUlGLjHDlyBBs2bMDOnTulZSkpKXBycioSIz09HZmZmdBoNIbdmP/HhIyIiIiIiKqFkJAQnD59GocOHdI7xunTp9GvXz/MmjULAQEBBmydfjhkkYiIiIiIqrzQ0FDs2LEDBw4cgKurq7Tc2dkZOTk5uHv3rqx8amoqnJ2dZcvOnj2LHj16YPz48Xj33Xdl65ydnWUzM+pi2NraGq13DGBCRkREREREVZgQAqGhodi6dSvi4uLg4eEhW+/l5QUzMzPs379fWpacnIzLly/Dx8dHWnbmzBn4+/tj1KhR+OCDD4rU4+PjI4sBALGxsbIYxsAhi0REREREVGWFhIQgJiYG27Ztg42NjXRdmJ2dHTQaDezs7BAcHIzw8HA4ODjA1tYWkydPho+PD7y9vQE8HKbYvXt3BAYGIjw8XIphYmKCevXqAQAmTpyIFStWYOrUqRg7dizi4uKwceNG2XVmxsAeMiIiIiKix5gQxf/l52tx585d5OdrSyyjz195rVq1CmlpafDz84OLi4v0t2HDBqnMkiVL8Nxzz2HgwIHw9fWFs7MztmzZIq3/7rvvcOPGDXz11VeyGB06dJDKeHh4YOfOnYiNjcXTTz+NRYsWYe3atUad8h5gDxkREREREVVhZZmB09LSEhEREYiIiCh2/ezZszF79uxHxvHz88OJEyfK28QKYQ8ZERERERGRQpiQERERERERKYQJGRERERERkUKYkBERERERESmEk3oQERERkVGo4uNlj4WfnyLtIKrK2ENGRERERESkECZkRERERERECmFCRkREREREpBAmZERERERERArhpB5EREREVCniVfFKN4GKo1IVu1gNwN4Y9QlhjKjVFnvIiIiIiIioylqwYAE6dOgAGxsbODo6on///khOTpaVycrKQkhICOrUqQNra2sMHDgQqamp0vpTp05h2LBhcHNzg0ajgaenJ5YtWyaLER8fD5VKVeQvJSXFqNvHhIyIiIiIiKqshIQEhISE4OjRo4iNjUVubi4CAgKQkZEh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w4YNkZeXh/z8/EeWz83NxcGDB+Hr6wszMzODt8fY8Y3JxMQEpqamBkkkmZARERERET0mVCoVzMzMypQAmZiYIC8vD5aWlkZJmIwdv7qoPoM1iYiIiIiIahgmZERERERERArhkEUiosdQwTHvQggFW0JERPR4Yw8ZERERERGRQthDRqQHVXy89G/h56dYO4iIiIioemMPGRERERERkUKYkBERERERESmEQxaJiIiIyGDi4wveKPeAYu0gqi7YQ0ZERERERKQQJmREREREREQKYUJGRERERESkECZkRERERERECinzpB4mJiblCqxSqZCXl1fuBhERERERET0uypyQCSGM2Q4iIiIiIqLHTrmmvW/evDkiIiIeWW7SpEn4448/9G4UERERERHR46BcCZmtrS26dev2yHI2NjZ6N4iIiIiIiOhxUeaE7MKFC7CwsChT2e+//x7Z2dl6N4qIiBSiUgEaDfDNN0q3hIiI6LFQ5oTM3d29zEGdnZ31agwREREREdHjpFxDFnW0Wi2ioqKwf/9+pKamyib8UKlU2L9/v8EaSEREREREVFPplZCFh4fj008/BfDf7IsqlQpCCKhUKsO1joiIiIiIqAbTKyH75ptvIIRA/fr14eHhAVNTvcIQERERERE91vTKpPLz8+Hq6opz586VeaIPIiIiIiIiklPr86SRI0ciMzMTubm5hm4PERERERHRY6PMPWRz586V/m1lZYUHDx6gTZs26Nu3L+zt7WVlZ86cabAGEhFRxcWr4pVuAhERERWjzAnZ7Nmzi0zY8ffff2PZsmVFyjIhIyIiIiIierQyJ2QNGzbkDIpEREREREQGVOaE7OLFi0ZsBhERERER0eOnXJN6zJkzB/Hx8cjMzDRWe4iIiIiIiB4b5Zr2fs6cOVCpVDA1NUW7du3QtWtX6a/wxB5ERERERERUunIlZBqNRpru/tixY/j555+xaNEiqFQqNG/eXErOhg4daqz2EhERERER1RjlGrKYlpaGI0eOYOHChQgKCoKdnR2EENBqtTh9+jRWrVqFl19+2VhtJSIiIiIiqlHKlZCZmprC29sbb731FrZv345bt27h119/xciRI2Fq+rCzTQhhlIYSEZFxqFT//REREVHlKteQRQDIzs7GsWPH8NNPP+Gnn35CYmIi7t+/LyVirq6uBm8kERGVjyo+Xvb4gDLNICIi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qlk4yyIRERERUQ0SHy//Bc/Pj7NiV2XsISMiIiIiIlIIEzIiIiIiIiKFMCEjIiIiIiJSCBMyIiIiIiIihTAhIyIiIiIiUggTMiIiIiIiIoUwISMiIiIiIlIIEzIiIiIiIiKFMCEjIiIiIiJSiKnSDSAiIiIiIv2p5qhkjw90U6ghpBf2kBERERERESmECRkREREREZFCmJAREREREREphAkZERERERGRQpiQERERERERKYQJGRERERERkUKYkBERERERESmECRkREREREZFCmJAREREREREphAkZERERERGRQpiQERERERERKcRU6QYQUc2jio+XPT6gTDOIiIiIqjz2kBERERERESmECRkREREREZFCmJAREREREREphNeQEREREVHVolIBGg3wzTew+9AOmdpMaZWYJRRsGJHhsYeMiIiIiIhIIewhIyIioseaSiV/LNgBQ0SViD1kRERERERECmFCRkREREREpBAOWSQiIiIivanmyMd8HuimUEOIqin2kBERERERESmECRkREREREZFCmJAREREREREphAkZERERERGRQpiQkWGoVICd3cN/6/5vgJAF/4iIiIiIahomZERERERERAphQkZERERERKQQJmREREREREQKYUJGRERERESkECZkRERERERECjFVugFERERERAVnVBbKNYOo0rGHjIiIiIiISCFMyIiIiIiIiBTChIyIiIiIiEghTMiIiIiIiIgUwkk9iCooXhUve+wn/BRpBxERERFVP+whIyIiIiIiUggTMiIiIiIiIoUwISMiIiIiIlIIryEjIiIiqsFUc1Syx2IWb7tMVJWwh4yIiIiIiEghTMiIiIiIClKpADs7pVtBRI8JJmREREREREQKYUJGRERERESkECZkRERERERECmFCRkREREREpBAmZERERERERAphQkZERERERKQQJmREREREVD662wLw9gBEFcaEjIiIiIiISCGmSjeAqr54VbzSTSAiIiIiqpHYQ0ZERERERKQQ9pARkUHEx6sKPDqgWDuIiIiIqhP2kBERERERESmECRkREREREZFCmJAREREREREpRNGE7ODBg3j++edRv359qFQqfP/997L1QgjMnDkTLi4u0Gg06NmzJ86dOycrc/v2bQwfPhy2trawt7dHcHAw7t+/Lyvzv//9D127doWlpSXc3Nzw0UcfFWnL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KkQ3DS4HPRIRERERlR97yIiIiIiIiBTChIyIiIiIiEghHLJIRNVCfLxK9tjPjwNliYiIqPpjDxkREREREZFCmJAREREREREphAkZERERERGRQngNGRHpRTVHfk3XgW4KNYSIiIioGmMPGRERERERkULYQ0ZEVYdKBWg0wDffKN0SIiIAgN2HdsjUZkqPxSzO8EpEhsUeMiIiIiIiIoUwISMiIiIiIlIIEzIiIiIiIiKF8BoyIqqWVPHx0r+Fn59i7SAiIiKqCCZkRKQoVYHZ83mpPBGR8cXH/3fi9fPjmZdIaRyySEREREREpBAmZERERERERAphQkZERERERKQQJmREREREREQKYUJGRGVnZyf/PxERERFVCBMyIiIiIiIihTAhIyIiIiIiUgjvQ0ay+5EAvCcJEREREVFlYUJGlYI3oSQiIiIiKopDFomIiIiIiBTChIyIiIiIiEghHLJI9BhSxcfLHgs/P0XaQURERPS4Y0JGRERENQavWSai6oZDFomIiIiIiBTChIyIiIiIiEghTMiIiIiIiIgUwmvIiAjxqnjp337CT/q3Sn7PcORoKqc9RERERI8L9pAREREREREphD1kRCSjKtwtBs5SRkRERGQs7CEjIiIiIiJSCHvIiIiIqEoq2GMvBHvriahmYkJG9JgoeLNU4IBi7SAiIiKi/3DIIhERERERkULYQ0aVThUfL3ss/PwUaUdNp5ojn5zjQDeFGkJERHrjZyZRzcceMiIiIiIiIoUwISOqKVQqwM7u4b91/yciIiKiKo1DFomIiGqgwvcU5CyFRERVExMyomqs4PctftUierzFq+KVbgIREemBCRkpruCXCH/4F1rLNIOISEd++wrAv8AtLHgzCyKi6okJGRERURVl96EdMrWZ0uPHebbUgiMCcjR2wDffAHZ2UL2dKSv3OO8jIqqemJBREYWn2OWvrkRElUilAjSahwkHERHVeJxlkYiIiIiISCHsISMiIlJQockQeeUsEdFjhj1kRERERERECmFCRkREREREpBAmZERERERERArhNWREOpzZrNoqfENcP+GnSDuIiIiIyosJGRERET0WCv944w//Ao84nQoRKYMJGREREVUJhRMmIqLHARMyIiJ6LKni42WPhZ+fIu0gIqLHGxMyIiIiyHtneB1i5SicFB9QphlERIpiQkZEVEni4/+7A7Cf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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# The following is a df that contains the efficiency (pSTeffTE) of each ST for supplying sES according to the age of the sST (sVin) \n", + "\n", + "efficiencyST = data_input['pSTEffTE'][data_input['pSTEffTE'].sST.str.startswith('sST_DSOTH_RES')].drop('sTE', axis=1)\n", + "\n", + "# The following is a df that contains the total sES Supplied (vQSTOut) by each sST according to the age of the sST (sVin) in a specific year (sYear) and season (sSeason) day (sDay) and hour (sHour)\n", + "TotalSTOut_2020 = data_results['vQSTOut'][(data_results['vQSTOut'].sST.str.startswith('sST_DSOTH_RES')) & (data_results['vQSTOut'].sYear=='y2020')]\n", + "TotalSTOut_2025 = data_results['vQSTOut'][(data_results['vQSTOut'].sST.str.startswith('sST_DSOTH_RES')) & (data_results['vQSTOut'].sYear=='y2025')]\n", + "TotalSTOut_2030 = data_results['vQSTOut'][(data_results['vQSTOut'].sST.str.startswith('sST_DSOTH_RES')) & (data_results['vQSTOut'].sYear=='y2030')]\n", + "TotalSTOut_2035 = data_results['vQSTOut'][(data_results['vQSTOut'].sST.str.startswith('sST_DSOTH_RES')) & (data_results['vQSTOut'].sYear=='y2035')]\n", + "TotalSTOut_2040 = data_results['vQSTOut'][(data_results['vQSTOut'].sST.str.startswith('sST_DSOTH_RES')) & (data_results['vQSTOut'].sYear=='y2040')]\n", + "TotalSTOut_2045 = data_results['vQSTOut'][(data_results['vQSTOut'].sST.str.startswith('sST_DSOTH_RES')) & (data_results['vQSTOut'].sYear=='y2045')]\n", + "TotalSTOut_2050 = data_results['vQSTOut'][(data_results['vQSTOut'].sST.str.startswith('sST_DSOTH_RES')) & (data_results['vQSTOut'].sYear=='y2050')]\n", + "\n", + "# Merge the two df on the columns sST, sES and sVin\n", + "TotalSTOut_2020 = pd.merge(TotalSTOut_2020, efficiencyST, on=['sST', 'sES', 'sVin'])\n", + "TotalSTOut_2025 = pd.merge(TotalSTOut_2025, efficiencyST, on=['sST', 'sES', 'sVin'])\n", + "TotalSTOut_2030 = pd.merge(TotalSTOut_2030, efficiencyST, on=['sST', 'sES', 'sVin'])\n", + "TotalSTOut_2035 = pd.merge(TotalSTOut_2035, efficiencyST, on=['sST', 'sES', 'sVin'])\n", + "TotalSTOut_2040 = pd.merge(TotalSTOut_2040, efficiencyST, on=['sST', 'sES', 'sVin'])\n", + "TotalSTOut_2045 = pd.merge(TotalSTOut_2045, efficiencyST, on=['sST', 'sES', 'sVin'])\n", + "TotalSTOut_2050 = pd.merge(TotalSTOut_2050, efficiencyST, on=['sST', 'sES', 'sVin'])\n", + "\n", + "\n", + "#multiply the vQSTOut by the pSTeffTE to get the total energy supplied by each ST\n", + "TotalSTOut_2020['TotalEnergySupplied'] = TotalSTOut_2020['vQSTOut']*TotalSTOut_2020['pSTEffTE']\n", + "TotalSTOut_2025['TotalEnergySupplied'] = TotalSTOut_2025['vQSTOut']*TotalSTOut_2025['pSTEffTE']\n", + "TotalSTOut_2030['TotalEnergySupplied'] = TotalSTOut_2030['vQSTOut']*TotalSTOut_2030['pSTEffTE']\n", + "TotalSTOut_2035['TotalEnergySupplied'] = TotalSTOut_2035['vQSTOut']*TotalSTOut_2035['pSTEffTE']\n", + "TotalSTOut_2040['TotalEnergySupplied'] = TotalSTOut_2040['vQSTOut']*TotalSTOut_2040['pSTEffTE']\n", + "TotalSTOut_2045['TotalEnergySupplied'] = TotalSTOut_2045['vQSTOut']*TotalSTOut_2045['pSTEffTE']\n", + "TotalSTOut_2050['TotalEnergySupplied'] = TotalSTOut_2050['vQSTOut']*TotalSTOut_2050['pSTEffTE']\n", + "\n", + "TotalSTOut_2020 = TotalSTOut_2020.groupby('sST')['TotalEnergySupplied'].sum()\n", + "TotalSTOut_2025 = TotalSTOut_2025.groupby('sST')['TotalEnergySupplied'].sum()\n", + "TotalSTOut_2030 = TotalSTOut_2030.groupby('sST')['TotalEnergySupplied'].sum()\n", + "TotalSTOut_2035 = TotalSTOut_2035.groupby('sST')['TotalEnergySupplied'].sum()\n", + "TotalSTOut_2040 = TotalSTOut_2040.groupby('sST')['TotalEnergySupplied'].sum()\n", + "TotalSTOut_2045 = TotalSTOut_2045.groupby('sST')['TotalEnergySupplied'].sum()\n", + "TotalSTOut_2050 = TotalSTOut_2050.groupby('sST')['TotalEnergySupplied'].sum()\n", + "\n", + "\n", + "# Create a figure and a set of subplots\n", + "fig, ax = plt.subplots(1, 1, figsize=(10, 5))\n", + "\n", + "# Set the bar width\n", + "barWidth = 0.15\n", + "\n", + "# Set the position of the bars on the x-axis\n", + "r1 = np.arange(len(TotalSTOut_2020))\n", + "r2 = [x + barWidth for x in r1]\n", + "r3 = [x + barWidth for x in r2]\n", + "r4 = [x + barWidth for x in r3]\n", + "r5 = [x + barWidth for x in r4]\n", + "r6 = [x + barWidth for x in r5]\n", + "r7 = [x + barWidth for x in r6]\n", + "r8 = [x + barWidth for x in r7]\n", + "r9 = [x + barWidth for x in r8]\n", + "\n", + "# Make the plot\n", + "plt.bar(r1, TotalSTOut_2020, color='b', width=barWidth, label='2020')\n", + "plt.bar(r2, TotalSTOut_2025, color='r', width=barWidth, label='2025')\n", + "plt.bar(r3, TotalSTOut_2030, color='g', width=barWidth, label='2030')\n", + "plt.bar(r4, TotalSTOut_2035, color='y', width=barWidth, label='2035')\n", + "plt.bar(r5, TotalSTOut_2040, color='c', width=barWidth, label='2040')\n", + "plt.bar(r6, TotalSTOut_2045, color='m', width=barWidth, label='2045')\n", + "plt.bar(r7, TotalSTOut_2050, color='k', width=barWidth, label='2050')\n", + "\n", + "\n", + "# Add xticks on the middle of the group bars\n", + "plt.xlabel('Technologies', fontweight='bold')\n", + "plt.xticks([r + barWidth for r in range(len(TotalSTOut_2020))], TotalSTOut_2020.index, rotation=90)\n", + "plt.ylabel('[GWh]', fontweight='bold')\n", + "plt.title('Total Energy delivered by Supply Residential Technology and Year')\n", + "# Create legend & Show graphic\n", + "plt.legend()\n", + "plt.grid()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sSTsYearvSTCapExc
98sST_DSTRA_LNP_BUSELEy20201.117219
126sST_DSTRA_RAIL_URBANy20208.535912
127sST_DSTRA_RAIL_URBANy20250.246661
128sST_DSTRA_RAIL_URBANy20301.857882
129sST_DSTRA_RAIL_URBANy20352.745627
130sST_DSTRA_RAIL_URBANy20402.266191
131sST_DSTRA_RAIL_URBANy20451.593680
132sST_DSTRA_RAIL_URBANy20501.601019
202sST_DSTRA_LNF_TRUBIELEy20500.530193
324sST_DSOTH_RESFRID_CONVy20304.456850
329sST_DSOTH_RESFRID_HEFFy202051.142432
330sST_DSOTH_RESFRID_HEFFy20252.078203
331sST_DSOTH_RESFRID_HEFFy20304.727636
\n", + "
" + ], + "text/plain": [ + " sST sYear vSTCapExc\n", + "98 sST_DSTRA_LNP_BUSELE y2020 1.117219\n", + "126 sST_DSTRA_RAIL_URBAN y2020 8.535912\n", + "127 sST_DSTRA_RAIL_URBAN y2025 0.246661\n", + "128 sST_DSTRA_RAIL_URBAN y2030 1.857882\n", + "129 sST_DSTRA_RAIL_URBAN y2035 2.745627\n", + "130 sST_DSTRA_RAIL_URBAN y2040 2.266191\n", + "131 sST_DSTRA_RAIL_URBAN y2045 1.593680\n", + "132 sST_DSTRA_RAIL_URBAN y2050 1.601019\n", + "202 sST_DSTRA_LNF_TRUBIELE y2050 0.530193\n", + "324 sST_DSOTH_RESFRID_CONV y2030 4.456850\n", + "329 sST_DSOTH_RESFRID_HEFF y2020 51.142432\n", + "330 sST_DSOTH_RESFRID_HEFF y2025 2.078203\n", + "331 sST_DSOTH_RESFRID_HEFF y2030 4.727636" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# SEE THE VALUES OF data_results['vSTCapExc'] DIFFERENT FROM ZERO\n", + "\n", + "data_results['vSTCapExc'][data_results['vSTCapExc'].vSTCapExc!=0]" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABNQAAAYSCAYAAADwZrYJAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdd3gU1fv38c+mB1LoHUInVOkQurRQpXelKVgAaepXbICoWAGlqYg0QQRUBAVRaVItKGADAUFAAUHpJUByP3/w7P5YUjckWcr7dV17Qc6cmbmn7MyZe2bnOMzMBAAAAAAAACBFfLwdAAAAAAAAAHAzIaEGAAAAAAAAeICEGgAAAAAAAOABEmoAAAAAAACAB0ioAQAAAAAAAB4goQYAAAAAAAB4gIQaAAAAAAAA4AESagAAAAAAAIAHSKgBAAAAAAAAHiChBgC3ocKFC8vhcLh9AgMDVahQIXXp0kXr1q1Lk/n07t1bDodDM2fOdCufOXOmHA6HevfunSbzQfry1vZy7qf79u3L0PkifTVo0EAOh0Nr1qzxdiipsm/fPjkcDhUuXDjesNtpn01qPdwIbvT4AAA3PxJqAHAbq127tnr16qVevXqpefPmiouL04IFC1S/fn2NGzfO2+F5xJkYvFGMGjVKDodDo0aN8nYoQIYhWQ4AAG4Xft4OAADgPffdd5/bhe+FCxd0//33a/bs2XrsscfUqlUrlSxZ0nsB4obQrl071axZU+Hh4Rk635UrV+rSpUvKnz9/hs4XAAAASA5PqAEAXIKCgjR58mRlzpxZsbGx+uijj7wdEm4A4eHhioyMVN68eTN0vsWKFVNkZKT8/f0zdL4AAABAckioAQDchISEqFSpUpIU7z1AK1asUKtWrZQrVy4FBAQoX7586tKli77//vs0mXdyPxdL6J04zp9WOl37bjjnMly6dEnvvfeeevToocjISIWFhSk4OFilSpXSww8/rL///jvBeV79vqetW7eqffv2ypEjhwIDA1WmTBm99tprMjO3cRwOh0aPHi1JGj16tFs8nv4UbtGiRWrWrJly5sypgIAA5c+fX3fffbd+/fXXJNdPXFyc3njjDVWoUEGZMmVS3rx59cADD+i///6TJMXExGjMmDGKjIxUcHCw8uXLp8GDB+vs2bPxppvUdvnqq6/UunVr5c6dW/7+/sqaNatKlCihu+++W19//bVb3ZiYGL3yyiuqUqWKQkNDFRAQoDx58qhatWp67LHHXLE5JfU+qnPnzunFF19U5cqVFRoaqkyZMqls2bJ66qmndPz48STXjZnp7bffVpUqVZQ5c2aFh4eradOm2rRpU4LbYNeuXerbt6+KFCmiwMBAhYSEKCIiQi1bttSMGTMSHCcp3377rTp37qx8+fIpICBAuXLlUuvWrfXll1/GqxsVFSWHw6H58+cnOr1JkybJ4XCoXbt28YZt2bJFPXr0UKFChRQYGKhs2bIpOjpay5YtS3BaV6/zTz75RA0bNlS2bNlS9M6zwoULq0+fPpKkWbNmue33DRo0SHCclH6nrrZy5Uq1b99eefPmda2/du3aJbr9kvLrr79q5MiRql27tvLnz6+AgABlz55djRs31oIFCzyeXlI82WdPnDghX19fZc2aVXFxcW7DFixY4Fqv127HmJgYZcqUSUFBQTp//rzbsMuXL+udd95RgwYNlC1bNgUGBqpIkSJ68MEHdeDAgUTj/vTTT1W/fn2FhoYqPDxcdevW1SeffOLx8u/YsUMOh0NZs2bVhQsXEq1XtWpVORwOt3mk5XZKybvVkjr2pHY9AgBuQQYAuO1ERESYJJsxY0aCw4sXL26S7OGHH3aVPfXUUybJHA6H1a5d27p162YVK1Y0Sebr62vTp0+PN51evXolOJ8ZM2aYJOvVq1eKyp327t1rkiwiIsJV9vHHH7vm4xz36s/Ro0fNzOzAgQMmycLDw61mzZrWqVMna9GiheXLl88kWc6cOW3Xrl3x5lm/fn2TZI8//rgFBARY6dKlrWvXrla/fn3z9fU1STZ48OB4y33HHXeYJLvjjjvc4pk2bVqCy3atS5cuWefOnU2SBQYGWq1ataxTp06u6QYHB9vy5csTXT/dunWz4OBga9asmbVt29Zy5cplkqxSpUp25swZq1OnjoWFhdldd91lrVq1svDwcJNkzZs3jxdLYttl5syZ5nA4zOFwWI0aNaxLly521113WeXKlc3X19dtvcTGxlqjRo1MkoWFhVnz5s2tW7du1rhxY9f++OOPP7pN31m+d+9et/J///3Xte85l6FDhw6WI0cOk2RFihSJN87V66ZXr17m7+9vDRs2tM6dO1vJkiVd63nz5s1u4/30008WFhZmkqxUqVLWvn1769Spk0VFRVlISIjdcccdKdmcLm+//bb5+Pi4tkW3bt2sVq1arv131KhRbvXfeustk2TR0dGJTrNy5comyZYsWeJWPmHCBNe8KlasaB07drQ6depYQECASbLRo0fHm5ZznQ8cONAkWdWqVa1bt25Wv359+/rrr5NctuHDh1vt2rVNkhUrVsxtvx87dqyrXmq+U1fPQ5L5+PhY9erVrVOnTlajRg1zOBzm6+tr7777bpIxXuvee+81SRYZGWnR0dHWpUsXi4qKcq23oUOHxhsnoePQtesvLfbZatWqmST75ptv3Mr79evn2l+ujW/lypUmye6880638lOnTlmDBg1MkoWEhFj9+vWtY8eOVqpUKZNk2bNntx9++CHe8owbN841r+rVq1u3bt2satWqJsmGDRuW6HpITFRUlEmy999/P8Hh27dvN0mWO3duu3Tpkqs8LbdTUtvPKbHtmNr1CAC4NZFQA4DbUFIJtW3btrkuUpwXp8uXLzdJFhQUZF988YVb/Xfeecckmb+/v/38889uwzIioebkvOhLzKlTp+yTTz6xmJgYt/KLFy/aiBEjTJK1aNEi3njOi39J9uabb7oNW7lypetC/sCBA27DRo4caZJs5MiRicaUlCeeeMIkWY0aNeyPP/5wG7Zw4ULz9fW1rFmz2vHjx13lzvXjTGjs27fPNezYsWNWokQJk2Tly5e36tWr27Fjx1zD//jjD8uaNatJsvXr17vNL7HtUqRIEZNk69atixf/kSNH3C4s165d60oinTp1Kl797777zi0es8Qvart06eJaN1ePc/r0aWvevLlJslq1armNc/W6iYiIsJ07d7qGXb582fr27WuSrGnTpm7j9enTxyTZc889Fy/mc+fO2dq1a+OVJ2b79u3m5+dnDofDZs+e7TZs2bJlrkTX1d+xkydPWqZMmczHx8cOHjwYb5rbtm1LMAHx+eefm8PhsBw5csSLcfv27VagQAGTZGvWrHEb5lznvr6+9sknn6R42ZyS+w6bpf479fbbb5skK168uG3bts1t2Nq1ay00NNQCAgLs999/T3G8a9assT179sQr37Fjh2sdXZvQSk1CLTX7rPO49Pzzz7uVFylSxPLly2fZs2e38uXLp2ic7t27myRr1aqVHTlyxG3Y+PHjTZKVKFHCLl++7Crftm2b+fr6mo+Pjy1cuNBtnPfee88cDofHCbVp06YlmSAeOnSoSbLhw4e7lafldrqehFpq1iMA4NZFQg0AbkMJJdROnDhhn332mRUrVswkWb58+ezMmTNmZq4ni4YNG5bg9Fq1amWSrF+/fm7lN1JCLTn58uUzHx+feMke58V/+/btExyvWbNmJileguR6Emr//vuvBQcHW1BQUIJJFDOzhx56yCTZxIkTXWVXJ40+++yzeOM4nzZxOBz2008/xRs+aNCgBJ9cSmy7ZMqUycLDw1O0TAsWLDDJ/anH5CR0Ufvnn3+aj4+PORyOeEkVM7ODBw9aUFCQSbINGza4yq9eN9c+yWVmdujQIddTahcvXnSVt2jRwiSlyVMnzqdsEtuXnE+FNWnSxK38nnvuMUn2wgsvxBtnyJAhJskeeeQRt/IaNWqYJFu0aFGC83Jujw4dOriVO9d53759PVk0F08Sap58p2JjY11Pk37//fcJjvfyyy8nmIxJLefTgY8++qhbuacJtdTus86nzRo0aOAq27Nnj2v9durUySTZ4cOHXcMTeqrt119/NYfDYfny5UswmW32f/v50qVLXWX33XefSbIuXbokOE6bNm08TqidOnUq0QTxxYsXLWfOnCYp3s2ZpHi6nVKbUEvtegQA3Lp4hxoA3Mb69OnjehdPlixZ1LJlS+3Zs0fFihXTsmXLlDlzZl2+fFkbNmyQpETf/3XvvfdKklavXp1Roafatm3bNG7cOA0aNEh9+/ZV79691bt3b12+fFlxcXHavXt3guO1bt06wfLSpUtLkv766680i3H16tU6f/68631BCXG+k2rjxo3xhvn5+alp06bxykuUKCFJKlSokMqVK5fo8MTeJ3et6tWr6+TJk+rZs6e2bNkS711PV6tcubJ8fX317rvvavLkyTp06FCK5nGtr7/+WnFxcapUqZIqVKgQb3j+/PkVHR0tKeH90c/PT82aNYtXnidPHmXNmlUxMTH6999/XeXVq1eXJD344INasWJFku9+So7zHWTJfY/WrVun2NhYV/nV7yW72qVLlzR37lxJUt++fV3lx44d07fffqvg4OBE99uk9h9J6tixY9ILkwY8+U79+OOP+vvvv1WsWDFVqVIlwfGSW6bEnDlzRgsXLtQTTzyh/v37u44JH374oSRp586dHk3vWqndZ2vXrq3g4GBt2rRJ586dk3TlnYWS1KRJEzVu3Nit7MSJE9qyZYuyZMmiqlWruqazbNkymZmaN2+u0NDQBGNMaN0599e77747wXF69eqV7LJfKzQ0VB07dlRcXJxmz57tNuyzzz7T0aNHVb16dZUtWzbeuOm9nZKT2vUIALh1+Xk7AACA99SuXVvFixeXJNfLvWvWrKlmzZrJz+/KKeLff/91JRGKFCmS4HSKFSsmKW2TSmnt7Nmzuueee/Txxx8nWe/UqVMJlhcqVCjB8rCwMEm6rkTLtf744w9JV16+fnWHCwk5evRovLK8efO6tt/VQkJCJCW+LM6LxJQuy5QpU9SqVSvNmTNHc+bMUWhoqKpVq6aGDRvqnnvucZtPsWLFNH78eD366KMaOHCgBg4cqIiICEVFRalVq1bq1KmTAgICkp2ncx9LbF90zuvqulfLmzdvor2GhoWF6fjx427L/+ijj2r9+vX66quv1KxZM/n7++uOO+5QvXr11LVrV1WrVi3ZmFMauzPuCxcu6N9//1WuXLkkXblIL1q0qHbu3KmNGzeqVq1akq68LP7o0aOqUaOGKwklSXv37pWZ6fz58woMDEwypoT2H0lJvrA9rXjynXJ+J/bs2ZOq70Rili5dqj59+rglUa+V2DEhpVK7zwYGBqpOnTr68ssvtW7dOkVHR+urr76Sw+FQ48aNXR2IfPXVV+rRo4dWrVqluLg43XnnnfLx+b975s51N336dE2fPj3JWK9edwcPHkwy7qSWJyl9+/bV7NmzNXPmTI0YMcJV7uzgw5lAvlpGbKfkpHY9AgBuXSTUAOA2dt9993nc66Q3JfUEVHJGjBihjz/+WJGRkXrxxRdVrVo15ciRw5XEqVWrljZt2pRo74JXX6CmN+dyFi9eXLVr106ybmRkZLyy5GJNq2UpXbq0du7cqS+++EKrVq3Sxo0btW7dOq1atUrPPvuspk+f7vZ0y6BBg9S5c2ctWbJE69ev1/r16zV//nzNnz9fI0eO1Lp165Q3b940iS0xni57pkyZ9OWXX+q7777T559/ro0bN2rjxo36/vvvNW7cOD300EOaPHlyOkV7hbOH1WeeeUYzZ850JdQSS0A495+QkBB16NAhVfMMDg6+johTxpNt4VymPHnyuJ7mSkyOHDlSNM2//vpLXbp00fnz5/XYY4+pR48eKly4sEJCQuTj46MvvvhC0dHRSfY4mt4aN26sL7/8Ul9++aWaNm2qVatWqXz58sqdO7ekK0kt5xNqzn+dT645OdddxYoVdccddyQ5vxo1aqT1IsRTr149FStWTL///rsrQfzPP/9o2bJlCgoKUteuXd3qe2M7JXSuudHWIwDA+0ioAQCSlD17dgUGBiomJkZ//PFHgj9Zct65T+zniSnlTG6dPn06weF//vlnqqe9YMECSdIHH3yQ4DLs2rUr1dNOawULFpQklSpVSjNnzvRuMMnw8/NTixYt1KJFC0lXnhIZN26cRo8erfvvv1/t2rVT5syZXfVz586tfv36qV+/fpKkHTt2qG/fvtq0aZMef/zxeD9rvJZzH3PucwlJq/3xatWqVXM9jXb58mUtXrxYPXv21JQpU9SxY0fdeeedyU4jf/782rNnj/74448Ef3LrjDsoKEjZsmVzG9arVy+NGjVKH3zwgV5//XWdOnVKy5cvV3BwcLwEhHP/cTgcevfddzM0GZxenMuUPXv2NPtOLF26VOfPn1e7du300ksvxRueVseE69lnr/5Z548//qh///3X7aeWjRs31rRp07Rjx45EE2rOdVe7dm1NmjTJo7j37Nmjffv2JfgTzH379qV4WldzJoiffvppzZgxQ7Vq1dJ7772ny5cvq3PnzsqSJYtb/bTeTsmdZy5dupTgT9JTux4BALeum7+FBQBIV35+fqpTp44kJXoh++6770pSipIKSXFeTO7YsSPB4Z999lmi4zp/xnf58uUEh//333+SpIiIiHjDVqxYoWPHjnkUa3KcF22JxZOURo0aKSAgQGvWrNE///yTpnGlt7CwMI0aNUpZsmTRuXPn9PvvvydZPzIyUv/73/8kSVu3bk12+vXq1ZOPj4+2bt2qbdu2xRt+6NAhff7555Kuf39MjJ+fnzp27Oh6UiolcUv/936l5L5HdevWjfeT3UKFCqlRo0Y6deqUPvroI1cCon379goPD3ermy9fPlWoUEGnT592rYuMcj37fVKcT5T++uuv+uWXX9JkmkkdE8xM8+bNS5P5XM8+W6lSJWXPnl3bt293xdOkSRPXcGfybPr06dq1a5cKFiyokiVLuk2jefPmkqQlS5Z49NP0+vXrS5LrPX3XuvYdaJ7o3bu3fHx8tGDBAp07dy7Jn3um9XbKmTOnAgIC9N9//yV4fF2xYkWC+29q1yMA4NZFQg0AkKzhw4dLkqZOnaqVK1e6DZs5c6aWLFkif39/DR48+LrmU716dYWFhenXX3/VnDlz3IYtXLhQb7zxRqLjFihQQJISvdh2vmNq4sSJbuU7d+7UAw88cD1hpyqepOTOnVuDBg3S2bNn1bp1a/3000/x6sTExGjJkiWJJh/T27lz5zRu3LgE3xW0bt06nThxQr6+vq71sGrVKi1btkyXLl1yq2tm+vTTTyUlfMF8rUKFCqlTp04yM91///1u71Q6e/as+vfvrwsXLqhWrVqun0ZejylTpiT4svPDhw/r+++/T3HckjR48GD5+flp8eLFeu+999yGffHFF3rrrbckSY888kiC4zs7HpgxY0aSCQhJeu6551zDly5dGm+4membb77RF198kaLYU8q5vX/99dc0na6/v79GjhwpM1O7du20fv36eHViY2O1atUqbd68OUXTdB4TFi1a5PZEUmxsrJ555pk0e7H89eyzDodDDRs2lJlp8uTJCggIUL169VzDGzVqJIfD4Xpi6tqn06QrSbkOHTrowIEDat++fYJPlp09e1Zz587VkSNHXGWDBg2Sr6+vFixYEO/dk/Pnz9fixYtTszokXdlPmjRpolOnTumJJ57Qzz//rEKFCqlhw4bx6qb1dvL393etw6eeesrt553btm3TwIEDExwvtesRAHAL80bXogAA74qIiDBJNmPGjBSP89RTT5kkczgcVqdOHevevbtVrlzZJJmvr69Nnz493ji9evVKcD4zZswwSdarV69444wfP94kmSSLioqyjh07WtmyZc3hcNjTTz9tkiwiIiLeeI888ohJshw5cljnzp3t3nvvtXvvvdeOHTtmZmYffvihORwOk2Tly5e3rl27WsOGDc3f398aNmxotWrVMkm2evVqt+nWr18/wXKnkSNHmiQbOXKkW/nhw4ctc+bMJslq165tvXv3tnvvvdfefffdxFaxm0uXLln37t1Nkvn4+FilSpWsQ4cO1qVLF6tdu7Zr2suXL3eNs3fv3kTXj5nZ6tWrTZLVr18/weGJbZeEyo8fP+6K7Y477rCOHTtat27dLCoqyrWen3nmGVd953YNCwuzBg0aWPfu3a1du3aufTE8PNx+/PFHt/k6h+3du9et/NixY3bHHXe4xmvbtq117NjRcubMaZKsSJEi8cZJbt0kNj/nfIoUKWKtW7e2Hj16WNOmTS04ONgkWcOGDe3SpUuJTvNab731lvn4+Jgkq1y5snXv3t1q167t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c4q2j5R27dDr2X8Ta9Mnt/8OGjRIn3/+uWbPnq077rgj1bE45ciRI8XrzcySPb8mtm8FBASoaNGiSd7sux7JtYV2794tM9PTTz+tp59+OsFp/PPPP8qfP3+S80npceBqGdWWcEpJGyGt5nW1yMhIVatWTXPnznUlp+fOnauaNWumqH1esmRJzZkzR7Gxsfr111/16aef6uWXX1b//v1VpEgRNW7c2HXdmdgDH87vgTORej3tMh8fn3hx58mTR1myZKFdlggSal70xx9/uL4gP/30U6qmERcXpyZNmuixxx5LcHjJkiUlSbly5dLWrVu1YsUKLV++XMuXL9eMGTPcuk6vV6+e9uzZo08++URffPGF3nnnHY0fP15vvvmm212tjBAZGSnpynpx3m1JTPHixeXn5+eWeLhWTEyMdu7cmWCi88CBA2ratKnCw8O1bNmyFN3lcj599sorr6hixYoJ1gkJCXH7++quxpMqkxJuYF1tyJAhat26tRYvXqwVK1bo6aef1tixY7Vq1SpVqlRJDodDixYt0ubNm7V06VKtWLFCffv21WuvvabNmzfHiy21kov/euNI6E5TSvd5T3Tu3FkbN27Uo48+qooVKyokJERxcXFq1qxZvCcNE4vreqV2X0ipsLAw5cuXTz///HOK6u/Zs0eNGjVSZGSkxo0bp4IFCyogIEDLli3T+PHj462X9FgnSUnN+nIeK1J6vF23bp3uuusu1atXT1OmTFHevHnl7++vGTNmaN68eamK+3plzZpVrVq1ciXUFi1apJiYmGTvgl4rU6ZMqlu3rurWrascOXJo9OjRWr58uXr16qW4uDjlypVLc+fOTXBcbz0lltH7GJBePD0eO5PM27dvT7TN4WwDXX1z1mnmzJn63//+pwceeEBPPfVU6oJORmLH5NQcq1PSdkhJuza9lulqqY0je/bskhJOLNasWVOFCxfWggUL1L17dy1dulTnz59Xly5dUr8wSrt2qKfn0tKlS2vx4sXavn276tWrl2CdpPbf0aNHa8qUKXrxxRd1zz33uA3z9LuUGsePH4+XdLxRJLf9nG21Rx55JNEniVKS9EmNjG5LeLON0LNnTw0ePFgHDx5UTEyMNm/erEmTJnk0DV9fX5UvX17ly5dXVFSU7rzzTs2dO1eNGzd2bcc5c+YkeHM2pU8cp1RKn9ajXXYFCTUviYuLU+/evRUWFqYhQ4bohRdeUMeOHdW+fXtJVw4yYWFhyZ4gihUrpjNnzqTorkFAQIBat26t1q1bKy4uTg899JDeeustPf30066DabZs2dSnTx/16dNHZ86cUb169TRq1KgkE2oRERHauXNnvPIdO3a4hnuqdevWGjt2rN57771kE2qZM2fWnXfeqVWrVunPP/9McH4LFixQTEyMWrVq5Vb+77//qmnTpoqJidHKlSuVN2/eFMVXrFgxSVdO5J7esUkrxYoV0/DhwzV8+HDt2rVLFStW1Guvvab33nvPVadmzZqqWbOmnn/+ec2bN089evTQ/PnzE9yeOXPmVKZMmRLdlj4+PvHuNKeUJ3EkJ6X7fEREhFavXq1z5865PaW2e/dut3rHjx/XypUrNXr0aD3zzDOuck9++uzc53bt2uX2k8WjR48meRfeUxEREfr111/j3S29dpkS06pVK7399tvatGmToqKikqy7dOlSxcTEaMmSJW53QJ2PlXsioXX5+++/K1OmTK4GVXrte1fLlCmTGjZsqFWrVunAgQPJTvPDDz9UUFCQVqxY4fZE5YwZMxKsn5LlTMq145uZdu/eHe8p4Z49e6pNmzb67rvvNHfuXFWqVMnt6T1POW80HDp0SNKV79hXX32l2rVrJ9lYch4Hf/755yQb5Ik1zCIiIrR9+3bFxcW5PaV2PecO4GbhyfG4efPm8vX11Zw5c9SzZ88E68yePVt+fn7xnoz65JNPdN9996l9+/aaPHlymsWfEZJrO6SkXXs15zFl586d8Z702LlzZ6qPOZ7GIV15sig4OFh79+5NcHjnzp31+uuv69SpU/rggw9UuHBh16sovM3Tc2mrVq00duxYzZ49O8GEWmxsrObNm6esWbOqdu3absMmT56sUaNGaciQIfrf//6X6PRT+l1Kjb1797o9FZeQq/etq9uBFy9e1N69e1N9rZDanyE6OWPx9/fP8OuVjGpLeBqTc16ero+k5t+1a1cNGzZM77//vs6fPy9/f//rSoAn1C6TriTwk4rbub2Tyx8k1S6Li4vTrl27XDdyJOnIkSM6ceIE7bJE8A41Lxk3bpw2btyot99+W2PGjFGtWrX04IMPun6j7+Pjo7Zt22rp0qX6/vvv443vvPPQuXNnbdq0SStWrIhX58SJE7p8+bIkxXt028fHx3WR5vwZ07V1QkJCVLx4cbefOSWkRYsW+vbbb7Vp0yZX2dmzZ/X222+rcOHCCd5tSk5UVJSaNWumd955R4sXL443/OLFi3rkkUdcfz/11FMyM/Xu3Vvnz593q7t371499thjyps3r+6//363GFu0aKG//vpLy5YtS/DnWompUqWKihUrpldffdXtHRdOzp+xpYdz587pwoULbmXFihVTaGioa1sdP3483t1F513txLanr6+vmjZtqk8++cTtJ2ZHjhzRvHnzVKdOHdcjxSmVmjiSk9J9Pjo6WpcuXXJ7B0FcXFy8Cwrn3b1r45wwYUKKY2rcuLH8/f01ceJEt+l4Mo2UiI6O1l9//aUlS5a4yi5cuOC2jEl57LHHlDlzZt133306cuRIvOF79uzR66+/Linh9XLy5MlEk0lJ2bRpk9s7xw4cOKBPPvlETZs2la+vb7rse4kZOXKkzEz33HNPgt/dLVu2uJ4q8PX1lcPhcHv/2b59+xI8JqVkOZMze/Zst5+tLFq0SIcOHVLz5s3d6jVv3lw5cuTQSy+9pLVr16b46bSVK1cmWO58Z4bzpyqdO3dWbGysxowZE6/u5cuXdeLECUlS06ZNFRoaqrFjx8Y7Jl2932TOnDnBn063aNFChw8f1gcffOA2/YkTJyokJCTZd8IBNzNPjscFCxZUnz599NVXX2nq1Knx6r755ptatWqV7r33XhUoUMBV/vXXX6tr166qV6+e5s6dG+/n1TeqlLQdUtKuvVbVqlWVK1cuvfnmm251li9frt9++00tW7b0ONbUxCFdSXBUrVo1wTa+dOVnnzExMZo1a5Y+//xzde7c2ePY0pMn59JatWqpcePGmjFjhj799NN4dZ988kn9/vvveuyxx9wSLx988IEefvhh9ejRQ+PGjUs0Fk++S546efKk9uzZo1q1aiVZr3HjxgoICNAbb7zhtu9Onz5dJ0+eTNW+JV05f0pynXc9lStXLjVo0EBvvfWWKzlztfS8XsmotoQnKleurCJFimjChAnx1mlyvwjJnDlzotshR44cat68ud577z3NnTtXzZo1S9FTjevWrUvwPZHXtsuio6MVFhamF154IcH6zu2YM2dO1atXT++++67279+f6PIltl85Xwdw7fWL8/uX2v34VscTaulg+fLlrjvsV6tVq5aKFi2q3377TU8//bR69+6t1q1bS7ryOH7FihVd72KQpBdeeEFffPGF6tevr/79+6t06dI6dOiQFi5cqPXr1ytLlix69NFHtWTJErVq1Uq9e/dWlSpVdPbsWf30009atGiR9u3bpxw5cui+++7Tf//9p4YNG6pAgQL6888/NXHiRFWsWNGVgS5TpowaNGigKlWqKFu2bPr++++1aNEiDRw4MMnlffzxx/X++++refPmevjhh5UtWzbNmjVLe/fu1YcffpjqBtzs2bPVtGlTtW/fXq1bt1ajRo2UOXNm7dq1S/Pnz9ehQ4f06quvSrryc9VXX31Vw4YNU4UKFdS7d2/lzZtXO3bs0LRp0xQXF6dly5a5vc+qR48e+vbbb9W3b1/99ttv+u2331zDQkJC1LZt20Rj8/Hx0TvvvKPmzZurbNmy6tOnj/Lnz6+//vpLq1evVlhYmJYuXZqq5U7O77//rkaNGqlz584qU6aM/Pz89PHHH+vIkSOuFwLPmjVLU6ZMUbt27VSsWDGdPn1a06ZNU1hYWJLvTnnuuef05Zdfqk6dOnrooYfk5+ent956SzExMXr55Zc9jjW1cSQlpft827ZtVb16dQ0fPly7d+9WZGSklixZov/++0/S/92dCQsLU7169fTyyy/r0qVLyp8/v7744otE7xonJGfOnHrkkUc0duxYtWrVSi1atNCPP/6o5cuXp+nPBO6//35NmjRJ3bp10+DBg5U3b17NnTvX9RLX5O7eFStWTPPmzVOXLl1UunRp9ezZU+XKldPFixe1ceNGLVy4UL1795Z0pYHjvOt+//3368yZM5o2bZpy5cqVYKMsKeXKlVN0dLQefvhhBQYGasqUKZKu/IzDKa33vcTUqlVLkydP1kMPPaTIyEjdc889KlGihE6fPq01a9ZoyZIleu655yRdaTiMGzdOzZo1U/fu3fXPP/9o8uTJKl68eII/MU/JciYlW7ZsqlOnjvr06aMjR45owoQJKl68eLxOJ/z9/dW1a1dNmjRJvr6+Cb5EOSFt2rRRkSJF1Lp1axUrVkxnz57VV199paVLl6patWqu81H9+vV1//33a+zYsdq6dauaNm0qf39/7dq1SwsXLtTrr7+ujh07KiwsTOPHj9d9992natWqqXv37sqaNau2bdumc+fOuS6mqlSpog8++EDDhg1TtWrVFBISotatW6t///5666231Lt3b23ZskWFCxfWokWLtGHDBk2YMMHjl0wDNxNPjseSNH78eO3YsUMPPfSQPv/8c9eTaCtWrNAnn3yi+vXr67XXXnPV//PPP3XXXXfJ4XCoY8eOWrhwodv8K1SokOw7cqUrbY6rn3x3yp07t5o0aZLKpU9aStoOKWnXXsvf318vvfSS+vTpo/r166tbt246cuSIXn/9dRUuXFhDhw71ONbUxOHUpk0bPfnkkzp16lS8m0aVK1dW8eLF9eSTTyomJibRp11OnjyZ4PaR5PGrADzhyblUutKmb9Sokdq0aaPu3burbt26iomJ0UcffaQ1a9aoS5cuevTRR131v/32W/Xs2VPZs2dXo0aN4v1s0HlNJXn+XZKkv/76K8H1dm37/6uvvpKZqU2bNkmuj5w5c2rEiBEaPXq0mjVrprvuuks7d+7UlClTVK1atVRvC2dHRw8//LCio6Pl6+vr1vlHSkyePFl16tRR+fLl1a9fPxUtWlRHjhzRpk2bdPDgQW3bti3ZaaTmOJBRbQlP+Pj4aOrUqWrdurUqVqyoPn36uK4Xf/nllwRv1jtVqVJFX331lcaNG6d8+fKpSJEibu8Q79mzpzp27ChJCSYRE/LSSy9py5Ytat++vet4/MMPP2j27NnKli2bq3ORsLAwTZ06Vffcc48qV66srl27KmfOnNq/f78+++wz1a5d2/UT0zfeeEN16tRR5cqVXe9h27dvnz777DNt3brVtSzSlWR2165d5e/vr9atW+uOO+5Qr1699Pbbb+vEiROqX7++vv32W82aNUtt27ZNshOK21pGdCV6u3B2+53YZ8aMGXb58mWrVq2aFShQwK17XTOz119/3STZBx984Cr7888/rWfPnpYzZ04LDAy0okWL2oABAywmJsZV5/Tp0zZixAgrXry4BQQEWI4cOaxWrVr26quv2sWLF83MbNGiRda0aVPLlSuXBQQEWKFChez++++3Q4cOuabz3HPPWfXq1S1LliwWHBxskZGR9vzzz7umkZQ9e/ZYx44dLUuWLBYUFGTVq1e3Tz/9NF49STZgwIAUr9Nz587Zq6++atWqVbOQkBALCAiwEiVK2KBBg2z37t3x6n/99dfWpk0by5Ejh/n7+1uhQoWsX79+tm/fvnh1k+o2O6FumRPy448/Wvv27S179uwWGBhoERER1rlzZ1u5cqWrTmLdY/fq1csyZ84cb5r169e3smXLuv6+trvyY8eO2YABAywyMtIyZ85s4eHhVqNGDVuwYIFrnB9++MG6detmhQoVssDAQMuVK5e1atXKvv/+e7d5SYrXpfMPP/xg0dHRFhISYpkyZbI777zTNm7c6FbHua9f26X9td1TpzSOhERERFjLli0THJaSfd7M7OjRo9a9e3cLDQ218PBw6927t23YsMEk2fz58131Dh48aO3atbMsWbJYeHi4derUyf7+++946yeprs5jY2Nt9OjRljdvXgsODrYGDRrYzz//bBEREW7dbF+7jszib3Ona7sgNzP7448/rGXLlhYcHGw5c+a04cOH24cffmiSbPPmzcms1St+//1369evnxUuXNgCAgIsNDTUateubRMnTnTrVn3JkiVWoUIFCwoKssKFC9tLL71k7777bryutpPaVs7v/HvvvWclSpSwwMBAq1SpktvyO6XlvpecLVu2WPfu3S1fvnzm7+9vWbNmtUaNGtmsWbPcuryfPn26K+7IyEibMWNGgt2pe7Kc13LG/v7779uIESMsV65cFhwcbC1btozX7bnTt99+a5KsadOmKVpeM7P333/funbtasWKFbPg4GALCgqyMmXK2JNPPmmnTp2KV//tt9+2KlWqWHBwsIWGhlr58uXtscces7///tut3pIlS6xWrVoWHBxsYWFhVr16dXv//fddw8+cOWPdu3e3LFmyxDu+HjlyxPr06WM5cuSwgIAAK1++vOtY5+Q8Br7yyispXlbgZpHS47GZWUxMjI0fP96qVKlimTNntkyZMlnlypVtwoQJ8dpqzuNKYp9rz/0JSWr8+vXru+oldg5L7NxwbVvQeVx3nldS0nZISbs2sfPCBx98YJUqVbLAwEDLli2b9ejRww4ePOhWJ7E22rXH/5TEkZgjR46Yn5+fzZkzJ8HhTz75pEmy4sWLJzi8fv36SW6ja2NOq3bo1VJ6LjW70nYbNWqUlS1b1nVeqV27ts2cOdPi4uLc6qbkmupaKf0uedL+79Kli9WpUyfevBIzadIki4yMNH9/f8udO7c9+OCDdvz4cbc6SbUlr3X58mUbNGiQ5cyZ0xwOh2u7JnVeTOj7vWfPHuvZs6flyZPH/P39LX/+/NaqVStbtGhRsjGk9DiQUJvVLP3bEs7v+cKFC+PNO7FjwPr1661JkyYWGhpqmTNntgoVKtjEiRNdwxNq5+3YscPq1atnwcHBJsmtbW92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ZMniVj937tw6fPhwotMbO3aswsPDXZ+CBQumZlGB6xZWoIACX35Zb86fr23btnk7HACAF3iUUHv99df11VdfacmSJdqxY4cWL16sxYsXa+fOnfr444/15Zdf6vXXX0+vWAEAAJBO0qOdV6pUKW3dulXffPONHnzwQfXq1Uu//vprqmMcMWKETp486focOHAg1dMCrlf//v31eK5cOhkd7e1QAABe4FFCbcaMGXrllVfUqlWreMPuuusuvfzyy3RKAAAAcBNKj3ZeQECAihcvripVqmjs2LG644479PrrrytPnjy6ePGiTpw44Vb/yJEjypMnT6LTCwwMdPUa6vwA3uLv76+7evVSvSNHtGXsWG+HAwDIYB4l1Hbt2uX2rotrNW7cWLt27bruoAAAAJCxMqKdFxcXp5iYGFWpUkX+/v5auXKla9jOnTu1f/9+RUVFXdc8gIxUY+xYbQ8NVcizzyr24kVvhwMAyEAeJdSCg4Pj3Um82qlTpxQUFHS9MQEAACCDpXU7b8SIEfr666+1b98+/fTTTxoxYoTWrFmjHj16KDw8XPfee6+GDRum1atXa8uWLerTp4+ioqLo4RM3FYePj3zGjVOpCxe0acAAb4cDAMhAHiXUoqKiNHXq1ESHT548mbuKAAAAN6G0buf9888/6tmzp0qVKqVGjRrpu+++04oVK9SkSRNJ0vjx49WqVSt16NBB9erVU548efTRRx9d93IAGa3cffdpU4EC+mfePJ0/f97b4QAAMoifJ5WffPJJNWjQQP/++68eeeQRRUZGysz022+/6bXXXtMnn3yi1atXp1esAAAASCdp3c6bPn16ksODgoI0efJkTZ48+XpDB7wu17Jlql+5skZPmKARI0Z4OxwAQAbwKKFWq1YtffDBB+rfv78+/PBDt2FZs2bV+++/r9q1a6dpgAAAAEh/tPOA1CtWvrwefOghbR4zRsfatlWO0qW9HRIAIJ15lFCTpHbt2ik6OlorVqxwvZi2ZMmSatq0qTJlypTmAQIAACBj0M4DUu+ZwYPl+8Yb2tali+pv3+7tcAAA6czjhJokZcqUSe3atUvrWAAAAOBltPOA1MletKhWN2+uOsuXa++KFSoSHe3tkAAA6cijTglWrVqlMmXK6NSpU/GGnTx5UmXLltW6devSLDgAAABkDNp5wPWr+d57+sfXV0f69vV2KACA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RlSRMaFGRERERERE9BF1vgWaJwK3N2Un1ixWA40aADt2AJnvlB0dEZU0JtSIiIiIiIiI8qnOgOzE2ssTQNUawMxvgBg94OyYMcjM4JQ1ooqCCTUiIiIiIiKiAnJqAxw+DOzeCSQZAC1WrkSsgQHO+vgg6x2nrBGVd0yoEREREREREX2ihr2AZk+Bm//7H17o66PFihX4zdISu3fvRlZWlrLDI6JiwoQaERERERERUSHV++47NPvnH0SsW4fQOnXQq1cvjLO1xblx4zhjjagcYkKNiIiIiIiIqIjUHzYMW0+dQlhYGDpkZcF56VLE6Onh3PjxTKwRlSNMqBEREREREREVsRYtWqDDo0e4sWYNknV14bxkCe7p6+Ov9et5KShROcCEGhEREREREVExaTBiBJyePcP1VasQbWICj+HD0bhxYwQvWMAZa0RlGBNqRERERERERMWs4ciR6PzoEUJOn0ZDXV24TZmCaH19nP/hBwjOWCMqc5hQIyIiIiIiIiohrVq1wpazZ3F9xQq81tbG5z//jCg9PZybOhVCCGWHR0T5xIQaERERERERUQlrOHo0mjx/jvBly5CqqYlL8+bByckJBwMCOGONqAxgQo2IiIiIiIhISRr5+KDxixdoePw4DAwMENKtG+7o6eHC1KlMrBGVYkyoERERERERESmZS9u2CAkJQb8VK5CmoYHP5s3DHT09XJw+nYk1olKICTUiIiIiIiKiUqLJ6NFo9OIFri1ejAx1dTSfMwcjHRxw6NAh3mONqBRhQo2IiIiIiIioFJFIJGg8bhwavHiByytW4GblyvDw8MA2S0tcmjmTM9aISgEm1IiIiIiIiIhKIYmKCpqOHo3ToaE4eegQ6qemotmsWbhtYIBLs2YxsUakREyoEREREREREZViEokEbp07o8GLF7i6cCEyVVTQbOZMXK5UCUf++ouXghIpARNqRERERERERGWAREUFTSZNQv2XL3Fl/nwEmZqiU+fOaNOsGS7PmcMZa0QliAk1IiIiIiIiojJEoqICp8mT8cO9ezh69CjaPX+OptOn46ahIS7PncvEGlEJYEKNiIiIiIiIqAySSCRo3749Jt+7h8tz5kAiBJpOm4abhoa4sHx5rktBMzMzERISgh07diAkJASZmZlKipyo7GNCjYiIiIiIiKgMk6iooOnUqaibnIzLs2dDIgR+9PXF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165ISkqCl5cXZs+ejVu3bqFu3br47rvv0L9/f6SmpuKHH37Au3fvcPLkSQDA3r17IZFI0KBBA6SkpGDGjBmIi4tDeHg4VFRUEBcXBzs7O9ja2mLx4sVo3LgxtLS0YGlpqeSjJSIiIqo4OM4jotKECTUiKleePn2KunXr4vnz59i7dy9u3ryJ0NBQHD16VFrn0aNHsLGxQVRUFOzt7XO18e+//8LMzAwRERGoV6+edKC1bNky+Pj4lOThEBEREdF/OM4jotKEl3wSUblSuXJlDB8+HI6OjujatSuuX7+O4OBg6OnpSRcHBwcAkE73j46ORp8+fVC9enUYGBjA1tYWAPDgwQOZtps2bVqix0JERERE/4/jPCIqTdSUHQARUVFTU1ODmlr211tKSgo8PDywcOHCXPVypvJ7eHigWrVq+N///gcrKytkZWWhXr16yMjIkKmvq6tb/METERERkUIc5xFRacGEGhGVa02aNMHevXtha2srHXy979mzZ4iKisL//vc/tGrVCgBw5syZkg6TiIiIiAqI4zwiUiZe8klE5Zq3tzeeP3+OPn364NKlS4iJicHRo0cxaNAgZGZmolKlSjAxMcH69etx7949nDx5EuPGjVN22ERERET0ERznEZEyMaFGROWalZUVwsLCkJmZifbt26N+/frw9fWFkZERVFRUoKKigp07d+LKlSuoV68exo4di0WLFik7bCIiIiL6CI7ziEiZ+JRPIiIiIiIiIiKiAuAMNSIiIiIiIiIiogLgQwmIiIiIqFzLzMzE27dvlR0GERGVIhoaGlBR4Rwj+nRMqBERERFRuSSEQEJCAl6+fKnsUIiIqJRRUVGBnZ0dNDQ0lB0KlVG8hxoRERERlUvx8fF4+fIlKleuDB0dHUgkEmWHREREpUBWVhaePHkCdXV1VK1alb8f6JNwhhoRERERlTuZmZnSZJqJiYmywyEiolLGzMwMT548wbt376Curq7scKgM4gXDRERERFTu5NwzTUdHR8mREBFRaZRzqWdmZqaSI6Gyigk1IiIiIiq3eBkPERHJw98PVFhMqBERERERERERERUAE2pERERERBWYRCLB/v37S3y/M2fORKNGjQrdzqZNm2BkZFTodoqbsvoZAFxdXeHr66uUfZdlZeXcIiLlYEKNiIiIiEiBzMxMhISEYMeOHQgJCSnWe+1IJJI8l5kz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9ddfMXr0aGWHU+FMnToV1apVy/PhBVS2qKurY+XKlcoOg8o5JtSIiIiIiIiUaNSoUXBycoKrqysGDx6s7HAqHCMjI/z4448fva8flR3fffddiT9AgioeXvJJREREROUOL+UhIqK88PcEFRZT8ERERERERERERAXAhBoREREREREREVEBMKFGRERERERERERUAEyoERERERERERERFQATakRERERERERERAXAhBoREREREREREVEBMKFGRERERERERERUAEyoEREREVGFIZGU7PIpBg4ciK5du0p/lkgkGDFiRK563t7ekEgkGDhwoEx5QkICRo8ejerVq0NTUxM2Njbw8PBAUFCQTL2zZ8+iU6dOqFSpErS0tFC/fn0sWbIEmZmZAIBNmzZBIpHkucTFxWHmzJnS16qqqrCxscGwYcPw/PnzXDGnpqbC2NgYpqamSE9P/7QOIiIiKgWYUCMiIiIiKsVsbGywc+dOpKamSsvS0tKwfft2VK1aVaZuXFwcnJyccPLkSSxatAgREREIDAyEm5sbvL29pfX27dsHFxcXWFtbIzg4GHfu3IGPjw/mzJmD3r17QwiBXr16IT4+Xro4Oztj6NChMmU2NjYAgLp16yI+Ph4PHjyAv78/AgMD8f333+c6lr1796Ju3bpwcHDA/v37i6fDiIiISoCasgMgIiIiIiLFmjRpgpiYGAQEBKBv374AgICAAFStWhV2dnYydUeOHAmJRIKLFy9CV1dXWl63bl0MHjwYAPD69WsMHToUXbp0wfr166V1vvvuO5ibm6NLly7YvXs3evXqBW1tbel6DQ0N6OjowMLCIleMampq0vIqVaqgR48e8Pf3z1Vvw4YN6NevH4QQ2LBhA3r16lWIniEiIlIezlAjIiIiIirlBg8eLJOg2rhxIwYNGiRT5/nz5wgMDIS3t7dMMi2HkZERAODYsWN49uwZJkyYkKuOh4cH7O3tsWPHjk+ONS4uDkePHoWGhoZMeUxMDM6dO4eePXuiZ8+eCA0Nxf379z95P0RERMrEhBoRERERUSnXr18/nDlzBvfv38f9+/cRFhaGfv36ydS5d+8ehBBwcHDIs627d+8CABwdHeWud3BwkNbJr4iICOjp6UFbWxt2dna4desWfvjhB5k6GzduRMeOHVGpUiUYGxvD3d1d7iw2IiKisoAJNSIiIiKiUs7MzAydO3fGpk2b4O/vj86dO8PU1FSmjhCiQG0WtH5eateujfDwcFy6dAk//PAD3N3dMXr0aOn6zMxMbN68WSYJ2K9fP2zatAlZWVlFFgcREVFJYUKNiIiIiKgMGDx4MDZt2oTNmzdL74f2vlq1akEikeDOnTt5tmNvbw8AiIyMlLs+MjJSWie/NDQ0ULNmTdSrVw8LFiyAqqoqZs2aJV1/9OhRPH78GL169YKamhrU1NTQu3dv3L9/P9fTR4mIiMoCJtSIiIiIiMqADh06ICMjA2/fvoW7u3uu9TmXUa5atQqvX7/Otf7ly5cAgPbt28PY2BiLFy/OVefgwYOIjo5Gnz59ChXrtGnT8Msvv+DJkycAsh9G0Lt3b4SHh8ssvXv3xoYNGwq1LyIiImVgQo2IiIiIqAxQVVVFZGQkbt++DVVVVbl1Vq1ahczMTDRv3hx79+5FdHQ0IiMjsWLFCjg7OwMAdHV1sW7dOhw4cADDhg3DjRs3EBcXhw0bNmDgwIHo3r07evbsWahYnZ2d0aBBA8ybNw///PMP/vzzTwwYMAD16tWTWfr374/9+/fj+fPnhdofERFRSVNTdgBERERERJQ/BgYGea6vXr06rl69irlz52L8+PGIj4+HmZkZnJycsGbNGmm97t27Izg4GHPnzkWrVq2QlpaGWrVqYerUqfD19YVEIil0rGPHjsXAgQNhZmYGXV1dtGnTJledNm3aQFtbG7///jvGjBlT6H0SERGVFIkoyruREhERERGVAmlpaYiNjYWdnR20tLSUHQ4REZUy/D1BhcVLPomIiIiIiIiIiAqACTUiIiIiIiIiIqICYEKNiIiIiIiIiIioAJhQIyIiIiIiIiIiKgAm1IiIiIiIiIiIiAqACTUiIiIiIiIiIqICYEKNiIiIiIiIiIioAJhQIyIiIiIiIiIiKgAm1IiIiIiIiIiIiAqACTUiIiIiIiIiIqICYEKNiIiIiCoOiaRkl08wcOBAdO3aVfqzRCLBiBEjctXz9vaGRCLBwIEDZcoTEhIwevRoVK9eHZqamrCxsYGHhweCgoJk6p09exadOnVCpUqVoKWlhfr162PJkiXIzMz8oMsk2L9/v0xZcHAwvvrqK5iZmUFLSws1atRAr169cPr0aZl6QgisX78en332GfT09GBkZISmTZti2bJlePPmjbRecnIypk6dCgcHB2hpacHCwgJt27ZFQEAAhBAF7EEiIqLix4QaEREREVEpZmNjg507dyI1NVValpaWhu3bt6Nq1aoydePi4uDk5ISTJ09i0aJFiIiIQGBgINzc3ODt7S2tt2/fPri4uMDa2hrBwcG4c+cOfHx8MGfOHPTu3TvPJNbq1avRpk0bmJiYYNeuXYiKisK+ffvQokULjB07Vqbut99+C19fX3h6eiI4OBjh4eGYPn06Dhw4gGPHjgEAXr58iRYtWmDLli2YMmUKrl69itOnT6NXr16YNGkSkpKSiqIbiYiIipSasgMgIiIiIiLFmjRpgpiYGAQEBKBv374AgICAAFStWhV2dnYydUeOHAmJRIKLFy9CV1dXWl63bl0MHjwYAPD69WsMHToUXbp0wfr166V1vvvuO5ibm6NLly7YvXs3evXqlSuWBw8ewNfXF76+vliyZInMugYNGmDMmDHS17t378a2bduwf/9+eHp6SsttbW3RpUsXJCcnAwB+/PFHxMXF4e7du7CyspLWs7e3R58+faClpVXgPiMiIipunKFGRERERFTKDR48GP7+/tLXGzduxKBBg2TqPH/+HIGBgfD29pZJpuUwMjICABw7dgzPnj3DhAkTctXx8PCAvb09duzYITeOvXv34u3bt5g0aZLc9ZL3LnPdtm0bateuLZNMe7+eoaEhsrKysHPnTvTt21cmmZZDT08PamqcA0BERKUPE2pERERERKVcv379cObMGdy/fx/3799HWFgY+vXrJ1Pn3r17EELAwcEhz7bu3r0LAHB0dJS73sHBQVpH3rYGBgawsLCQlu3duxd6enrSJSIiAgAQHR2N2rVr5xnLv//+ixcvXnw0ZiIiotKG/91DRERERFTKmZmZoXPnzti0aROEEOjcuTNMTU1l6hT05v2ferN/yQcPW3B3d0d4eDgeP34MV1dX6UMN8tM+HzhARERlFRNqRERERERlwODBgzFq1CgAwKpVq3Ktr1WrFiQSCe7cuZNnO/b29gCAyMhItGjRItf6yMhI1KlTR+62tWrVQlJSEhISEqSz1PT09FCzZs1cl2ba29t/NBYzMzMYGRl9tB4REVFpw0s+iYiIiIjKgA4dOiAjIwNv376Fu7t7rvXGxsZwd3fHqlWr8Pr161zrX758CQBo3749jI2NsXjx4lx1Dh48iOjoaPTp00duDN27d4e6ujoWLlz40Xi/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F54/f47MzEy14lGnNZu6cdWsWRO3bt3CgQMHEBwcjKtXr6JGjRr48ccf1VqeiIhI21ihRkRERERUSHh4eEAmkyE6Olrl/OjoaBQpUgReXl4AgOvXr+dZnqenJ9LS0pCcnCylmZmZwcPDA87OzmrH5eXlhbS0NCQlJeWbL7+Y5PT19VGjRg2MGDECe/fuxcSJE/Hjjz8iIyND7biIiIi0hRVqRERERESFhI2NDerVq4eFCxfixYsXCvOSk5Oxdu1atG7dGhUqVICPjw9mzJiBrKwspXJSU1MBAMHBwdDX18fUqVPfK67g4GAYGBjgl19+UTlfvr527dohNjYWO3bsUMojhEBaWlqu6/Dx8cGbN2/w8uXL94qViIjoY2CFGhERERFRITJ//ny8evUKgYGBOHLkCO7cuYPIyEjUq1cPJUqUwKRJkyCTyRAREYHY2FjUqFEDu3btwq1bt3D58mVMmjRJGhSgZMmSmDFjhjSiZlRUFBISEnDhwgXMnTsXAKCrq5tvTE5OTpg1axbmzJmDrl274vDhw0hMTMTx48fRs2dP6VXNkJAQtG7dGm3btsXkyZNx7tw5JCYm4s8//0TdunURFRUFAKhVqxaWLFmC8+fPIyEhAbt27cL333+P2rVrw8LC4gPtWSIiooIjE5p0wEBERERE9Al4+fIl4uPj4erqCiMjI22Ho7HExESMGzcOkZGRSElJgYODA4KCgjBu3DjY2NhI+WJjYzFp0iTs378f//77L4oVK4Zq1aph2LBhqFixopRv//79mDlzJk6fPo0nT57AxsYG/v7+6NWrFwIDAxXWPX78eGzfvh2XLl1Simv//v2YPn06zpw5gxcvXsDFxQWNGzfG4MGDpQELsrKysHTpUqxYsQJXr16Fnp4ePD090alTJ3Tv3h3GxsaYMmUK/vjjD8TExCA9PR3FixdH48aNMXbsWIXtIyL6UD71+wRpHyvUiIiIiOizwz+UiIgoL7xP0PviK59EREREREREREQaYIUaERERERERERGRBlihRkREREREREREpAFWqBEREREREREREWmAFWpEREREREREREQaYIUaERERERERERGRBlihRkREREREREREpAFWqBEREREREREREWmAFWpEREREREREREQaYIUaERERERERERGRBlihRkRERERfDNlHnt5FWFgYZDKZ0nTjxg3UqlUL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vb09Bg8eLJWliUmTJuHgwYNKLccAID09HcnJybh79y5OnTqFESNGoFevXujduzdq166da5mjRo3C/fv3sX//foX0hQsX4s2bN6hUqRI2btyI6OhoxMTEYM2aNbh+/brSPiAiIsoPK9SIiIiI6MshPvL0Dtzc3HDhwgXUrl0bQ4YMQdmyZVGvXj0cOHAAixYtAvC25VlUVBRu376NGjVqoFSpUpg1axZ++OEHbNiwQaGfsf79+2Pv3r149OgRgoOD4enpiUaNGiE+Ph6RkZHw9fVVWH+pUqVQrFgxhen8+fO5xjt06FCYmZlpvJ1eXl7o0qULXr58qTTv119/RbFixeDu7o4WLVrg2rVr2LhxIxYuXJhnmdbW1hgxYoRSme7u7rh48SLq1q2LUaNGoXz58qhUqRLmzZuHoUOH4scff9Q4fiIi+rLJhKYdHhARERERFXIvX75EfHw8XF1dYWRkpO1wiIiokOF9gt4XW6gRERERERERERFpgBVqREREREREREREGmCFGhERERERERERkQZYoUZERERERERERKQBVqgRERERERERERFpgBVqREREREREREREGmCFGhERERERERERkQZYoUZERERERERERKQBVqgRERERERERERFpgBVqREREREREREREGmCFGhERERF9MWQy2Ued3lVycjL69+8PNzc3GBoawsnJCU2aNMGBAwekPCdOnECjRo1QpEgRGBkZwdfXFzNnzkRmZqZSeVFRUWjcuDFsbW1hZGQEd3d3tG7dGkeOHJHyHDp0KNftSE5OBgCMHz8eMpkMvXr1Uij/0qVLkMlkSEhIUEhftWoVKleuDBMTE5ibmyMgIAB//vmnND8sLCzP/efi4gIAqFWrFsLDw5W2a+XKlbCyslL4LJPJ0KBBA4V8qampkMlkOHTokMb7hYiISBVWqBERERERFSIJCQnw8/PDwYMHMW3aNFy5cgWRkZGoXbs2+vbtCwDYtm0bAgIC4OjoiKioKFy/fh0DBw7ETz/9hDZt2kAIIZW3cOFC1KlTBzY2Nti4cSNiYmKwbds2VKtWDYMGDVJaf0xMDJKSkhQmOzs7ab6RkRGWL1+OuLi4PLdj6NCh6NmzJ1q3bo3Lly/jzJkz+Oabb9CsWTPMnz8fADBnzhyF9QBARESE9Pns2bMa7z89PT3s378fUVFReebTdL8QERFlp6ftAIiIiIiI6H/69OkDmUyGM2fOwNTUVEovU6YMunTpgufPn6N79+5o2rQpli5dKs3v1q0b7O3t0bRpU/z+++9o3bo1bt++jfDwcISHh2PmzJkK6ylXrhwGDBigtH47OzuFVl85lSpVCnZ2dvjhhx/w+++/q8xz6tQpzJgxA3PnzkX//v2l9EmTJuHly5cYPHgwmjVrBicnJ1haWiosa2VlBQcHhzz3UV5MTU0REhKCkSNH4vTp0yrzvMt+ISIiyo4t1IiIiIiIComUlBRERkaib9++CpVpclZWVti7dy8eP36MoUOHKs1v0qQJvLy8sH79egDAli1b8Pr1awwfPlzl+t71tdSff/4ZW7Zswblz51TOX79+PczMzNCzZ0+leUOGDMHr16+xZcuWd1q3OsaPH48rV65g8+bNKud/qP1CRERfDlaoEREREREVEjdu3IAQAqVLl841T2xsLADA29tb5fzSpUtLeWJjY2FhYaHQ4mvLli0wMzOTpitXrigs7+joqDC/TJkySuv46quvEBISghEjRuQao7u7OwwMDJTmFS9eHBYWFlKM6lq4cKFCXGZmZkp9uWVfx8CBA/HDDz/gzZs3KuPTdL8QERFlx1c+iYiIiIgKiex9nxVU3pytrQIDA3Hp0iXcu3cPtWrVUhrE4OjRozA3N5c+6+vrqyz3p59+gre3N/bu3avQx5qm8amrffv2+OGHHxTStm7dismTJ6vMP2LECCxZsgQrVqxASEiI0nxN9wsREVF2bKFGRERERFRIeHp6QiaT4fr167nm8fLyAgBER0ernB8dHS3l8fT0RFpamjRKJwCYmZnBw8MDzs7OKpd3dXWFh4eHNOWWz93dHd27d8fIkSOVKs+8vLxw69YtZGRkKC13//59PHnyRIpRXZaWlgpxeXh4qKzIk7OyssKoUaMwYcIEpKenK8x7l/1CRESUHSvUiIiIiIgKCWtrawQGBmLBggV4/vy50vzU1FTUr18f1tbWmDFjhtL8nTt3Ii4uDm3btgUABAcHQ19fH1OnTv0g8Y4dOxaxsbHYsGGDQnqbNm3w7NkzLFmyRGmZ6dOnQ19fHy1btvwgMWXXv39/6OjoYM6cOQrpH3q/EBHR54+vfBIRERERFSILFixA9erVUaVKFUycOBHlypXDmzdvsG/fPixatAjR0dFYsmQJ2rRpgx49eqBfv36wsLDAgQMHMGzYMAQHB0uvOJYsWRIzZszAwIEDkZKSgrCwMLi6uiIlJQVr1qwBAOjq6iqs/+HDh3j58qVCmo2NjcpXP+3t7TF48GBMmzZNId3f3x8DBw7EsGHDkJGRgaCgILx+/Rpr1qzBnDlzMHv2bDg5ORXkblPJyMgIEyZMQN++fRXS32W/EBERZccWakRERET0xRBCfNTpXbi5ueHChQuoXbs2hgwZgrJly6JevXo4cOAAFi1aBOBtC6uoqCjcvn0bNWrUQKlSpTBr1iz88MMP2LBhg0L/YP3798fevXvx6NEjBAcHw9PTE40aNUJ8fDwiIyPh6+ursP5SpUqhWLFiCtP58+dzjXfo0KEwMzNTSp89ezYWLlyI9evXo2zZsqhUqRKOHDmC7du3o3///u+0b95FaGgo3NzclNI13S9ERETZyURB9xZKRERERKRlL1++RHx8PFxdXWFkZKTtcIiIqJDhfYLeF1uoERERERERERERaYAVakRERERERERERBpghRoREREREREREZEGWKFGRERERERERESkAVaoEREREdFni+NvERGRKrw/0PtihRoRERERfXb09fUBAOnp6VqOhIiICqOMjAwAgK6urpYjoU+VnrYDICIiIiIqaLq6urCyssLDhw8BACYmJpDJZFqOioiICoOsrCw8evQIJiYm0NNjtQi9G545RERERPRZcnBwAACpUo2IiEhOR0cHJUuW5I8t9M5kgi8OExEREdFnLDMzE69fv9Z2GEREVIgYGBhAR4e9YNG7Y4UaERERERERERGRBlgdS0REREREREREpAFWqBEREREREREREWmAFWpEREREREREREQaYIUaERERERERERGRBlihRkREREREREREpAFWqBEREREREREREWmAFWpEREREREREREQaYIUaERERERERERGRBlihRkREREREREREpAFWqBEREREREREREWmAFWpEREREREREREQaYIUaERERERERERGRBlihRkREREREREREpAFWqBEREREREREREWmAFWpEREREREREREQaYIUaERERERERERGRBlihRkREREREREREpAFWqBEREREREREREWmAFWpEREREREREREQaYIUa0Sdo/PjxkMlkBV7uypUrIZPJkJCQUOBlf0zPnj1Dt27d4ODgAJlMhvDwcI3LkO/jf//9t+AD/Aji4uJQ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bEF4eDju3r0rzXd0dMScOXPQokULLUZJRERERERERJ8jtQYlGDRoEExNTdUudNGiRShatOg7B0WkDnllWnBwsEJlGgDcu3cPwcHB2Lp1q5aiIyIiIiIiIqLPlVoVahUrVsS///4LAHBzc8Pjx48/aFBE6sjMzER4eLjKeUIIAEB4eDgyMzM/YlRERERERERE9LlTq0LNysoK8fHxAICEhARkZWV90KCI1HH06FGllmnZCSFw584dHD169CNGRURERERERESfO7X6UGvZsiUCAgJQrFgxyGQyVKpUKdcO32/dulWgAdKnTTZB9uEKv6JettrzawOHP0wIYpz4MAUTERERERERUaGlVoXa0qVL0aJFC9y4cQMDBgxA9+7d1R7Jk+iDMSvgfEREREREREREalCrQg0AGjRoAAA4f/48Bg4cyAo1Uovw/HBlZ7oDLn8A91IAVe3EZAAcrYH4uoCuWi83ExERERERERHlT+NqhoiICJibm+PGjRvYs2cPXrx4AeB/ncATfSy6OsCcTm//n9uLpbM7sTKNiIiIiIiIiAqWxlUNKSkpqFOnDry8vNCoUSMkJSUBALp27YohQ4YUeIBEeWlRGdgcDpSwVp43rd3b+UREREREREREBUnjCrXw8HDo6+vj9u3bMDExkdJbt26NyMjIAg2OSB0tKgMJc4CoH4B1fYF9IwHv4sCWswAHpCUiIiIiIiKigqZ2H2pye/fuxZ49e+Do6KiQ7unpicTExAILjEgTujpALZ//fV7YGag9CVh5BOhSS2thEREREREREdFnSOMWas+fP1domSaXkpICQ0PDAgmK6H3V8gHaVweOx2o7EiIiIiIiIiL63GhcoVajRg389ttv0meZTIasrCz88ssvqF27doEGR/Q+lncHlvfQdhRERERERERE9LnR+JXPX375BXXq1MG5c+eQkZGB4cOH4+rVq0hJScHx48c/RIxE78RQHxAC2HYOcCkKfOWq7YiIiIiIiIiI6HOgcQu1smXLIjY2Ft988w2aNWuG58+fo0WLFrh48SLc3d0/RIxE7+z/2LvzuKiq/4/j7wFZVUBcwAW3THFfy8jKVBIrt9Ryq8wsW3DFLX9alqVmVi6pZeaSpWlufc3Mcs/cMlNzJTVzBxcUFBUR7u+PkdGRxRkZGMDX8/G4D2bOPffezz1zGWY+nHtOsiENXyS9Nl1K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io6TRjKBLQDgHubu7q66detq1apVlrLk5GStWrVKISEhaW4TEhJiVV+SVqxYYVU/JZl24MABrVy5UoULF86aEwAAAHAwuxNqYWFhatOmjSSpQoUK2r9/v86ePavTp0+rcePGdu3r3XfflclkslqCg4Mt669evarw8HAVLlxYBQoUUNu2bVP9pxPISvcFSG+1kMYslSJPOjsaAACcJyIiQlOnTtXXX3+tffv26Y033lB8fLy6du0qSXrxxRc1ePBgS/3evXtr+fLl+uSTT7R//369++67+vPPP9WjRw9J5mRau3bt9Oeff2r27NlKSkpSVFSUoqKidO0aswIBAICczeaEWlJSkv7++29duXIl1TovLy/t2rXL0nPNHlWrVtWpU6csy++//25Z17dvX/3444+aP3++1q1bp5MnT1qSeUB2GdRCKuUv9Zrl7EgAAHCe9u3b6+OPP9Y777yjWrVqaceOHVq+fLll4oGjR4/q1KlTlvoPP/yw5syZoy+//FI1a9bUggUL9MMPP6hatWqSpBMnTmjJkiU6fvy4atWqpeLFi1uWjRs3OuUcAQAAbGUyDMOwpeLMmTM1ceJEbdmyRa6urlbrrl+/roceekh9+vTR888/b/PB3333Xf3www/asWNHqnWxsbEqWrSo5syZo3bt2kmS9u/fr8qVK2vTpk166KGHbDpGXFycfH19FRsbm+GYHJkyx5Q1+80pOtl0iaQtj7TNun2Sez4p5P7bVmSmbQAAOVa2fH5ApvE6AQAAeznq84PNPdSmTZum/v37p0qmSVK+fPk0cOBAffnll3YHcODAAZUoUULly5dX586ddfToUUnStm3blJiYqNDQUEvd4OBglS5dWps2bUp3fwkJCYqLi7NagMxqWNmcTEtOlq5yFwoAAAAAAPc0mxNqkZGRGfYKe+CBB7Rv3z67Dl6/fn3NnDlTy5cv1+eff26Z4ODixYuKioqSu7u7/Pz8rLYJCAhQVFRUuvscNWqUfH19LUtQUJBdMQHpMQypyUjp7QXOjgQAAAAAADhTPlsrxsfHZ9jb6+LFi7p8+bJdB3/yySctj2vUqKH69eurTJky+v777+Xl5WXXvlIMHjxYERERludxcXEk1eAQJpMUWk16d5H00mNS1VLOjggAAAAAADiDzT3U7r///gwHiP399991//23DzBlHz8/P1WsWFEHDx5U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+vTTT9W4cWPVrVtXM2bM0MaNG7V582aHHR/IyUqVKqXt27enSjYDAAAAAADnsTuh9uGHH6pfv35au3atzp07p7i4OKvFXuHh4Xr66acVGhpqVb5t2zYlJiZalQcHB6t06dLatGlTuvtLSEjIdExATmIymXTw4EH1799fycnJzg4HAAAAAIB7nt23fDZr1kyS1KRJE6tywzBkMpmUlJRk877mzp2rv/76S1u3bk21LioqSu7u7qlucwsICFBUVFS6+xw1apTee+89m2MAcoPjx4/rk08+UZUqVfTyyy87OxwAAAAAAO5pdifU1qxZ45ADHzt2TL1799aKFSvk6enpkH1K0uDBgxUREWF5HhcXp6CgIIftH3CGxx9/XJ07d9agQYPUunVrZtQFgHvMkiVL7N7miSeekJeXVxZEAwAAALsTag0bNnTIgbdt26bTp0+rTp06lrKkpCT99ttvmjhxon755Rddu3ZNFy5csOqlFh0drcDAwHT36+HhIQ8PD4fECOQkH3/8sX788UcNGTJEn3/+ubPDAQBko9atW9tV32Qy6cCBAypfvnzWBAQAAHCPs3kMtY8++shqMoINGzYoISHB8vzixYt68803bT5wkyZNtGvXLu3YscOy1KtXT507d7Y8dnNz06pVqyzbREZG6ujRowoJCbH5OEBeERgYqOHDh+vbb7/VmTNnnB0OACCbRUVFKTk52abF29vb2eECAADkaTYn1AYPHqyLFy9anj/55JM6ceKE5fnly5c1ZcoUmw9csGBBVatWzWrJnz+/ChcurGrVqsnX11fdunVTRESE1qxZo23btqlr164KCQnRQw89ZPNxgLwkPDxce/fuVdGiRZ0dCgAgG3Xp0sWu2zeff/55+fj4ZGFEAAAA9zabb/k0DCPD51lh7NixcnFxUdu2bZWQkKCwsDBNnjw5y48L5FT58uVTUFCQLl26pF27dtFbEwDuETNmzLCrPkMDAAAAZC2be6hlh7Vr12rcuHGW556enpo0aZJiYmIUHx+vRYsWZTh+GnCveOedd/T0009z6ycA3INefvllq7sGUsTHxzMTNAAAQDbJUQk1ALYZPHiwJOmtt95yciQAgOz29ddfW41rm+LKlSuaNWtWlh570qRJKlu2rDw9PVW/fn398ccfGdafP3++goOD5enpqerVq2vZsmVW6w3D0DvvvKPixYvLy8tLoaGhOnDgQFaeAgAAgEPYNcvnV199pQIFCkiSrl+/rpkzZ6pIkSKSlOZ/SgFkjaJFi2rkyJF644031K1bNz388MPODgkAkMXi4uJkGIYMw9DFixfl6elpWZeUlKRly5apWLFiWXb8efPmKSIiQl988YXq16+vcePGKSwsTJGRkWked+PGjerYsaNGjRql5s2ba86cOWrdurX++usvVatWTZJ50qsJEybo66+/Vrly5fT2228rLCxMe/futTo/AACAnMZk2DgYWtmyZWUyme5Y7/Dhw5kOypHi4uLk6+ur2NjYrBucd86d2yVX65SJ8fJomyyTlJSkhx56SImJifrrr7/k4kKHUwBwlGz5/GAnFxeXDD+LmUwmvffeexoyZEiWHL9+/fp64IEHNHHiRElScnKygoKC1LNnzzR7TLdv317x8fFaunSppeyhhx5SrVq19MUXX8gwDJUoUUL9+vVT//79JUmxsbEKCAjQzJkz1aFDhzvGlBNfJwAAkLM56vODzT3U/vvvv7s+CADHc3V11ZdffqmYmBiSaQBwD1izZo0Mw1Djxo21cOFC+fv7W9a5u7urTJkyKlGiRJYc+9q1a9q2bZtlyAHJnOALDQ3Vpk2b0txm06ZNioiIsCoLCwvTDz/8IMn8T9ioqCiFhoZa1vv6+qp+/fratGlTmgm1hIQEJSQkWJ7HxcVl5rQAAADuml23fALIWWrXri3JPAbNlStX5O3t7eSIAABZpWHDhpLMiaigoKBs/WfK2bNnlZSUpICAAKvygIAA7d+/P81toqKi0qwfFRVlWZ9Sll6d240aNUrvvffeXZ0DAACAI91VQm3VqlUaO3as9u3bJ0mqXLmy+vTpY/UfRgDZp3379vLw8NA333zj7FAAAFnk6NGjksy3dh4/fjzdeqVLl86ukLLd4MGDrXq9xcXFKSgoyIkRAQCAe5XdCbXJkyerd+/eateunXr37i1J2rx5s5566imNHTtW4eHhDg8SQMaaNWumbt266ZVXXrH0YAAA5C3lypWzPE4ZAvfWMdUMw5DJZFJSUpLDj12kSBG5uroqOjraqjw6OlqBgYFpbhMYGJhh/ZSf0dHRKl68uFWdWrVqpblPDw8PeXh43O1pAAAAOIzd9wqMHDlSY8eO1XfffadevXqpV69emjNnjsaOHauRI0dmRYwA7uCll15SSEiIwsPDlZiY6OxwAABZwGQyKSgoSG+//ba2bt2q7du366+//rIsKc+zgru7u+rWratVq1ZZypKTk7Vq1SqFhISkuU1ISIhVfUlasWKFpX65cuUUGBhoVScuLk5btmxJd58AAAA5hd0JtQsXLqhZs2apyps2barY2FiHBAXAPi4uLpo8ebL27dunCRMmODscAEAWOH78uN544w3NnTtXTz/9tL755hu5u7urZs2aVktWiYiI0NSpU/X1119r3759euONNxQfH6+uXbtKkl588UWrSQt69+6t5cuX65NPPtH+/fv17rvv6s8//1SPHj0kmROEffr00QcffKAlS5Zo165devHFF1WiRAm1bt06y84DAADAEexOqLVs2VKLFy9OVf6///1PzZs3d0hQAOxXq1YtvfXWW0xMAAB5VGBgoAYNGqT9+/drwYIFOn/+vOrXr6+HHnpIU6dOVXJycpYev3379vr444/1zjvvqFatWtqxY4eWL19umVTg6NGjOnXqlKX+ww8/rDlz5ujLL79UzZo1tWDBAv3www+qVq2apc7AgQPVs2dPde/eXQ888IAuXbqk5cuXy9PTM0vPBQAAILNMRsogHDb64IMP9PHHH6tBgwaW7vibN2/Whg0b1K9fP/n4+Fjq9urVy7HR3oW4uDj5+voqNjbWKjaHmmO6c53crJNdl4g12gYAkAtly+cHB4iOjlbHjh21bt06nTlzRv7+/s4OKVvlltcJAADkHI76/GD3pATTpk1ToUKFtHfvXu3du9dS7ufnp2nTplmem0ymHJFQA+41CQkJGjBggFq2bMnMuwCQR23cuFHTp0/X/PnzValSJU2aNEl+fn7ODgsAAOCeYXdC7fDhw1kRBwAHcXd3186dO/XLL7/o77//ZjY0AMgjTp06pVmzZmnGjBk6f/68OnfurA0bNljdQgkAAIDsYXdCDUDOZjKZNGnSJNWqVctye/apU6dUvHhxPfroo3J1dXV2iACAu1C6dGmVLFlSXbp0UcuWLeXm5qbk5GT9/fffVvVq1KjhpAgBAADuHXaPoZbbMIaaAzCGWvpy8BhqrVq10pIlS6zKSpUqpfHjx6tNmzZOigoAcoecODaXi8vNuaRMJvPf19s/xplMJiUlJWVrXM6UE18nAACQszltDDUAOd+iRYv0448/pio/ceKE2rVrpwULFpBUA4BchmE3AAAAcg4S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UVG6cOGCs0MBAAC5gJ+fnwIDA2Uyme5Yl4QaAAAA8qSUZFqxYsXk7e1t04djAABw7zEMQ5cvX9bp06clScWLF7/jNiTUAAAAkOckJSVZkmmFCxd2djgAACCH8/LykiSdPn1axYoVu+Ptn0xKAAAAgDwnZcw0b29vJ0cCAAByi5TPDbaMvUpCDQAAAHkWt3kCAABb2fO5gYQaAAAAAAAAYAfGULuB6dQBIHPsnWYaAIAUa9euVaNGjXT+/Hn5+fll67FNJpMWL16s1q1bZ2o/ZcuWVZ8+fdSnTx+HxIW79/jjj6tWrVoaN26cs0NxqsjISDVs2FAHDhxQwYIFnR2O07z11luKj4/XZ599dse6OanNeE9xrGvXrqlixYpasGCB6tWr55B93vMJNaZTBwDHsWeaaQBwhux+ezIM+7eJiorSiBEj9NNPP+nEiRMqVqyYatWqpT59+qhJkyaWehs3btQHH3ygTZs26cqVK7r//vvVtWtX9e7d2/IPjv/++0/vv/++Vq9eraioKJUoUULPP/+8hgwZInd391THTklsZWTNmjV6/PHH01w3c+ZM9enTJ1d9tj516pQKFSqU6f1s3bpV+fPnd0BE946yZcvqyJEjqcpHjRqlt9566673u2jRIrm5uVmVHTx4UCNGjNCKFSt05swZlShRQg899JD69etn9eV66dKlGjNmjP766y8lJSWpatWqCg8P10svvWSps3PnTn344Yf6/fffdfbsWZUtW1avv/66evfubXXMa9euady4cZo9e7YOHDggb29vVapUSa+88oqef/75VDE62uDBg9WzZ0+rxJBhGJo6daqmTZumPXv2KF++fKpQoYKef/55de/eXd7e3nr33Xf13nvvpdpfpUqVtH///lTljz/+uNatW5duHA0bNtTatWvv6vU+fPiwhgwZorVr1yomJkZFihRR3bp1NXr0aG3evFldu3bNsA0OHz6s/v37q3z58urbt6/Kly+fYf202uxO0vvc+91336lDhw427+d2ab2nbN++XSNHjtRvv/2m2NhYBQUF6fHHH9eAAQNUsWJFS72vv/5aEydO1J49e+Tq6qo6depowIABat68uaXO2rVrNXbsWP3xxx+Ki4vT/fffrwEDBqhz585Wx4yLi9Po0aO1cOFC/ffff/Lz81O1atX05ptv6plnnnHY5/6M/v6cOnVKgYGBmdq/u7u7+vfvr0GDBmnVqlWZ2leKez6hxnTqAJB5dzPNNAAgtf/++08NGjSQn5+fxowZo+rVqysxMVG//PKLwsPDLV9mFy9erOeee05du3bVmjVr5Ofnp5UrV2rgwIHatGmTvv/+e5lMJu3fv1/JycmaMmWKKlSooN27d+vVV19VfHy8Pv7441THf/jhh3Xq1CnL8969eysuLk4zZsywlPn7+2d9Q2SjzH5JS1G0aFGH7Ce3SUxMzFRiaPjw4Xr11VetyjLbM+j2a/TPP/9UkyZNVK1aNU2ZMkXBwcG6ePGi/ve//6lfv36WZNBnn32mPn36aNCgQfr888/l7u6u//3vf3r99de1e/duy+/Mtm3bVKxYMX377bcKCgrSxo0b1b17d7m6uqpHjx6SzMm0sLAw7dy5U++//74aNGggHx8fbd68WR9//LFq166tWrVqZeo8M3L06FEtXbo0Va+sF154QYsWLdLQoUM1ceJEFS1aVDt37tS4ceNUtmxZS0/NqlWrauXKlVbb5suXdvpg0aJFunbtmiTp2LFjevDBB7Vy5UpVrVpVkqyS9/a83omJiXriiSdUqVIlLVq0SMWLF9fx48f1888/68KFC2rfvr2aNWtmqd+mTRtVq1ZNw4cPt5QVLVpUrq6uCgsL0+eff64xY8bY3Wa2mDFjhlUskjLd2/b295SlS5eqbdu2CgsL0+zZs3Xffffp9OnTmj9/vt5++23NmzdPktS/f39NnDhRH3zwgVq3bq3ExER9++23atWqlcaPH2+5Rjdu3KgaNWpo0KBBCggI0NKlS/Xiiy/K19fXkni7cOGCHnnkEcXGxuqDDz7QAw88oHz58mndunUaOHCgGjdu7PBexZGRkfLx8bEqK1asmEP23blzZ/Xr10979uyxXJ+ZYtzDrl+/buzdu9c4e/ass0MBgDzh7Nmzxt69e43r1687OxQA97grV64Ye/fuNa5cuWJVbu4zln2LvZ588kmjZMmSxqVLl1KtO3/+vGEYhnHp0iWjcOHCRps2bVLVWbJkiSHJmDt3brrH+Oijj4xy5crZFE+XLl2MVq1aWZ7HxMQYL7zwguHn52d4eXkZzZo1M/755x/DMAxjzZo1hiSrZdiwYYZhGMasWbOMunXrGgUKFDACAgKMjh07GtHR0Zb9pmybco5pOX/+vNGtWzejSJEiRsGCBY1GjRoZO3bssKwfNmyYUbNmTWPatGlGUFCQkT9/fuONN94wrl+/bowePdoICAgwihYtanzwwQdW+5VkLF682DAMw0hISDDCw8ONwMBAw8PDwyhdurQxcuRIwzAMIzk52Rg2bJgRFBRkuLu7G8WLFzd69uxp2U+ZMmWMsWPHWp4fOXLEaNmypZE/f36jYMGCxrPPPmtERUWlinfWrFlGmTJlDB8fH6N9+/ZGXFycpc78+fONatWqGZ6enoa/v7/RpEmTNK+NFGvXrjUeeOABw93d3QgMDDQGDRpkJCYmGoZhGFOmTDGKFy9uJCUlWW3TsmVLo2vXrpbnP/zwg1G7dm3Dw8PDKFeunPHuu+9a9pHSXpMnTzZatGhheHt7W17j25UpU8YYPny40aFDB8Pb29soUaKEMXHixFR1bm2z26VcF8uXLzdq1apleHp6Go0aNTKio6ONZcuWGcHBwUbBggWNjh07GvHx8ZbtGjZsaPTu3dswDPPrVrVqVaNu3bqpzt0wbv5eHT161HBzczMiIiJS1ZkwYYIhydi8eXO6sb755ptGo0aNLM9Hjx5tuLi4GH/99VequteuXbO8jj///LPRoEEDw9fX1/D39zeefvpp4+DBg5a6hw8fNiQZ3333nRESEmJ4eHgYVatWNdauXZtuLIZhGGPGjDHq1atnVTZv3jxDkvHDDz+kqp+cnGxcuHDBMIyb1+bdSIl3+/btqdbd6fW+3fbt2w1Jxn///WdT/Vtf99t9/fXXRqlSpTLc/vY2i42NNTw9PY1ly5ZZ1Vu0aJFRoEAByzV363tIWmbMmGH4+voaP/74o1GxYkXDy8vLaNu2rREfH2/MnDnTKFOmjOHn52f07NnT6jP0re0VHx9vFClSxGjdunWax0i5jjdt2mRIMiZMmJCqTkREhOHm5mYcPXo03Vifeuopq/eDN954w8ifP79x4sSJVHUvXrxoeW+w9T1+6dKlRvXq1Q0PDw+jfv36xq5du1LVSe/vwJUrV4wqVaoYr776qqXs4MGDRoECBYxp06ZZyqZNm2ZUqVLF8j4YHh5utZ9GjRoZQ4cOTbcN0vv8kJZ7elICplMHAMeyZ5ppAIC1mJgYLV++XOHh4WneOpjSC+DXX3/VuXPn1L9//1R1WrRooYoVK+q7775L9zixsbF33cvspZde0p9//qklS5Zo06ZNMgxDTz31lBITE/Xwww9r3Lhx8vHx0alTp3Tq1ClLjImJiXr//fe1c+dO/fDDD/rvv/+sbqGzxbPPPqvTp0/r559/1rZt21SnTh01adJEMTExljqHDh3Szz//rOXLl+u7777TtGnT9PTTT+v48eNat26dRo8eraFDh2rLli1pHmPChAlasmSJvv/+e0VGRmr27NkqW7asJGnhwoUaO3aspkyZogMHDuiHH35Q9erV09xPcnKyWrVqpZiYGK1bt04rVqzQv//+q/bt21vVO3TokH744QctXbpUS5cu1bp16/Thhx9KMt/i1LFjR7388svat2+f1q5dqzZt2shI5z7iEydO6KmnntIDDzygnTt36vPPP9e0adP0wQcfWNrv3LlzWrNmjWWblGsu5Rav9evX68UXX1Tv3r21d+9eTZkyRTNnztSIESOsjvXuu+/qmWee0a5du/Tyyy+n95JpzJgxqlmzprZv36633npLvXv31ooVK9Ktn553331XEydO1MaNG3Xs2DE999xzGjdunObMmaOffvpJv/76a7q9inbs2KE9e/aoX79+cnFJ/fU35fdqwYIFSkxMTPP36rXXXlOBAgXs+r2aPXu2QkNDVbt27VR13dzcLL/j8fHxioiI0J9//qlVq1bJxcVFzzzzjJKTk622GTBggPr166ft27crJCRELVq00Llz59KNZ/369anGiZo9e7YqVaqkVq1apapvMpnk6+ub7v6coWjRonJxcdGCBQuUlJSUqX09+OCDOn78uP77779069zeZj4+PmrevLnmzJljVW/27Nlq3bq1XXmEy5cva8KECZo7d66WL1+utWvX6plnntGyZcu0bNkyffPNN5oyZYoWLFiQ5va//PKLzp49q4EDB6a5PuU6/u6771SgQAG99tprqer069dPiYmJWrhwYbpx3nodJycna+7cuercubNKlCiRqm6BAgUsvRZtfY8fMGCAPvnkE23dulVFixZVixYtbP7e4OnpqdmzZ+vrr7/W//73PyUlJen555/XE088YXkf+vzzzxUeHq7u3btr165dWrJkiSpUqGC1nwcffFDr16+36Zh3dMeUWx5mT+YRAHBnvK8CyClyYw+1LVu2GJKMRYsWZVjvww8/zPC/+C1btjQqV66c5roDBw4YPj4+xpdffmlTTLf2UPvnn38MScaGDRss68+ePWt4eXkZ33//vWEYN3ti3MnWrVsNScbFixcNw7hzz4T169cbPj4+xtWrV63K77vvPmPKlCmGYZh71Xh7e1v18AoLCzPKli1r1TOpUqVKxqhRoyzPdUvvkp49exqNGzc2kpOTU8XwySefGBUrVjSuXbuWZoy39ib59ddfDVdXV6ueIHv27DEkGX/88Ue68Q4YMMCoX7++YRiGsW3bNrt65/zf//2fUalSJavYJ02aZBQoUMBy/q1atTJefvlly/opU6YYJUqUsKxv0qSJpUdeim+++cYoXry45bkko0+fPneMp0yZMkazZs2sytq3b288+eSTVnXc3d2N/PnzWy2//fabYRg3r4uVK1dathk1apQhyTh06JCl7LXXXjPCwsIsz2/tqZTSKyutnmK3ev311zO8dmvUqGEV+602bNhg5MuXz/jll18sZV5eXkavXr0yPGZazpw5Y0iy9NxJ6fH14YcfWuokJiYapUqVMkaPHp3ufmrWrGkMHz7cqqxy5cpGy5Yt7xjDsGHDDBcXl1Svy2uvvXbHbe/UQy2j1zstEydONLy9vS29UocPH2712t8qox5qsbGxhqQMe/al1WaLFy+26o2W0mvt559/ttSRZHh6eqY6ryNHjhiGYX5flGTV8/C1114zvL29Le+BhmF+v7q1jW99Txk9erQhyYiJiUk3fsMwjGbNmmXYu9DHx8d444030lw3b948w93d3di9e7dhGIYRHR1tSDI+/fTTDI+ZlvTe42/tPX3u3DnDy8vLmDdvnlWd29uxSpUqVvv+6KOPjCJFihg9evQwihcvbnXHYYkSJYwhQ4ZkGNv48eONsmXLprueHmoAAABALmPYOYOBvfVPnDihZs2a6dlnn001hpEt9u3bp3z58ql+/fqWssKFC6tSpUrat29fhttu27ZNLVq0UOnSpVWwYEE1bNhQknnMIlvs3LlTly5dUuHChVWgQAHLcvjwYR06dMhSr2zZslbjMQUEBKhKlSpWPZMCAgIsY37e7qWXXtKOHTtUqVIl9erVS7/++qtl3bPPPqsrV66ofPnyevXVV7V48WJdv349zf3s27dPQUFBCgoKspRVqVJFfn5+Vm11e7zFixe3xFazZk01adJE1atX17PPPqupU6fq/Pnz6bbRvn37FBISYjUmdIMGDXTp0iUdP35cknn8oIULFyohIUGSuadNhw4dLO2zc+dODR8+3KqNX331VZ06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/LHOnDljOZa9f//uv/9+tWrVSq+++qqmTJmiggUL6q233lLJkiUtg5yXLVtWly5d0qpVq1SzZk15e3urdOnScnd312effabXX39du3fv1vvvv2/XsUNDQxUSEqLWrVvro48+UsWKFXXy5En99NNPeuaZZ2y+BfFOPv30UxUvXly1a9eWi4uL5s+fr8DAQPn5+WnmzJlKSkpS/fr15e3trW+//VZeXl6pek+kxFu9enV17txZ48aN0/Xr1/Xmm2+qYcOGNse6ZcsWrVq1Sk2bNlWxYsW0ZcsWnTlzJt0vn2+++abGjRunnj17qkePHoqMjNSwYcMUERFhlQzr3Lmzmjdvrj179uj555+32sc777yj5s2bq3Tp0mrXrp1cXFy0c+dO7d692+4eQZI5offRRx+pdevWWrFihebPn6+ffvrJqs7FixcVFRVlVebt7S0fHx+7j5cWk8mkGTNmKDQ0VI8++qiGDBmi4OBgXbp0ST/++KN+/fVXrVu3TqVLl9ZHH32kfv36ydPTUy+88ILc3Nz0v//9T//3f/+nfv36WW533r17txo3bqywsDBFRERY4nd1dbX0fOnTp49++uknNWnSRO+//74eeeQRFSxYUH/++adGjx6tadOmqUaNGipcuLC+/PJLFS9eXEePHtVbb72V5nlMmjRJ999/vypXrqyxY8fq/PnzGU4IERYWpldeeUVJSUlydXWVJD333HNavHixOnbsqKFDh6pp06YqWrSodu3apbFjx6pnz55q3bq1JHPS7vbXxWQyKSAgIFOvhz2v944dOzRs2DC98MILqlKlitzd3bVu3TpNnz5dgwYNsuu469ev16OPPpphL6a02kySHnvsMQUGBqpz584qV66c1W3vKS5cuJDqvAoWLOiw3pz58+fXV199pWeffVYtW7ZUr169VKFCBZ09e1bff/+9jh49qrlz5yokJES9e/fWgAEDdO3aNbVu3VqJiYn69ttvNX78eI0bN85yK/qaNWvUvHlz9e7dW23btrXE7+7ubpmYYMSIEVq7dq3q16+vESNGqF69enJzc9P69es1atQobd261a73+OHDh6tw4cIKCAjQkCFDVKRIEcs1l+L06dOpOuYULlxYbm5umjRpkjZt2qS///5bQUFB+umnn9S5c2dt3rxZ7u7uevfdd/X666+rWLFievLJJ3Xx4kVt2LBBPXv2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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "vEmiCO2CapTraExc = data_results['vEmiCO2CapTraExc'].vEmiCO2CapTraExc\n", + "vEmiCO2CapEleExc = data_results['vEmiCO2CapEleExc'].vEmiCO2CapEleExc\n", + "vEmiCO2CapIndTEExc = data_results['vEmiCO2CapIndTEExc'].vEmiCO2CapIndTEExc\n", + "vEmiCO2CapIndProExc = data_results['vEmiCO2CapIndProExc'].vEmiCO2CapIndProExc\n", + "vEmiCO2CapOthExc = data_results['vEmiCO2CapOthExc'].vEmiCO2CapOthExc\n", + "vEmiCO2CapRefExc = data_results['vEmiCO2CapRefExc'].vEmiCO2CapRefExc\n", + "\n", + "vEmiCO2CapExc = data_results['vEmiCO2CapExc'].vEmiCO2CapExc\n", + "vEmiNOxCapExc = data_results['vEmiNOxCapExc'].vEmiNOxCapExc\n", + "vEmiSOxCapExc = data_results['vEmiSOxCapExc'].vEmiSOxCapExc\n", + "vEmiPM25CapExc = data_results['vEmiPM25CapExc'].vEmiPM25CapExc\n", + "\n", + "\n", + "fig, axs = plt.subplots(2, 2, figsize=(15, 15))\n", + "fig.suptitle('Pollutant emissions over the allowed value', fontsize=16)\n", + "# Separate the graphs of the first column from the second column\n", + "plt.subplots_adjust(hspace=1)\n", + "\n", + "\n", + "\n", + "# Make a bar plot in the first subplot\n", + "axs[0, 0].bar(years, vEmiCO2CapTraExc, label='Transport emissions over pEmiCO2CapTra (vEmiCO2CapTraExc)', color='blue')\n", + "axs[0, 0].bar(years, vEmiCO2CapEleExc, label='Electricity production emissions over pEmiCO2CapEle (vEmiCO2CapEleExc)', color='red', bottom=vEmiCO2CapTraExc)\n", + "axs[0, 0].bar(years, vEmiCO2CapIndTEExc, label='IndustryTE emissions over pEmiCO2CapIndTE (vEmiCO2CapIndTEExc)', color='green', bottom=[sum(x) for x in zip(vEmiCO2CapTraExc, vEmiCO2CapEleExc)])\n", + "axs[0, 0].bar(years, vEmiCO2CapIndProExc, label='IndustryPro emissions over pEmiCO2CapIndPro (vEmiCO2CapIndProExc)', color='orange', bottom=[sum(x) for x in zip(vEmiCO2CapTraExc, vEmiCO2CapEleExc, vEmiCO2CapIndTEExc)])\n", + "axs[0, 0].bar(years, vEmiCO2CapOthExc, label='Residential and commercial emissions over pEmiCO2CapOth (vEmiCO2CapOthExc)', color='brown', bottom=[sum(x) for x in zip(vEmiCO2CapTraExc, vEmiCO2CapEleExc, vEmiCO2CapIndTEExc, vEmiCO2CapIndProExc)])\n", + "axs[0, 0].bar(years, vEmiCO2CapRefExc, label='Refinery processes (CE_Ref) emissions over pEmiCO2CapRef (vEmiCO2CapRefExc)', color='purple', bottom=[sum(x) for x in zip(vEmiCO2CapTraExc, vEmiCO2CapEleExc, vEmiCO2CapIndTEExc, vEmiCO2CapIndProExc, vEmiCO2CapOthExc)])\n", + "\n", + "#Add a title and labels for the first subplot\n", + "axs[0, 0].set_title('Excess of CO2 emissions regarding Carbon Cap by Sector')\n", + "axs[0, 0].set_xlabel('Year')\n", + "axs[0, 0].set_ylabel('[MtCO2]')\n", + "axs[0, 0].legend()\n", + "axs[0, 0].legend(loc='center left', bbox_to_anchor=(0, -0.5))\n", + "\n", + "\n", + "\n", + "# Make a bar plot in the second subplot\n", + "CE_Ele_Emissions_2020 = data_results['vEmiCO2CE'][(data_results['vEmiCO2CE'].sYear=='y2020') & (data_results['vEmiCO2CE'].sCE.isin(data_input['sCE_Ele'].sCE_Ele))].vEmiCO2CE.sum()*1e-3\n", + "CE_Ele_Emissions_2025 = data_results['vEmiCO2CE'][(data_results['vEmiCO2CE'].sYear=='y2025') & (data_results['vEmiCO2CE'].sCE.isin(data_input['sCE_Ele'].sCE_Ele))].vEmiCO2CE.sum()*1e-3\n", + "CE_Ele_Emissions_2030 = data_results['vEmiCO2CE'][(data_results['vEmiCO2CE'].sYear=='y2030') & (data_results['vEmiCO2CE'].sCE.isin(data_input['sCE_Ele'].sCE_Ele))].vEmiCO2CE.sum()*1e-3\n", + "CE_Ele_Emissions_2035 = data_results['vEmiCO2CE'][(data_results['vEmiCO2CE'].sYear=='y2035') & (data_results['vEmiCO2CE'].sCE.isin(data_input['sCE_Ele'].sCE_Ele))].vEmiCO2CE.sum()*1e-3\n", + "CE_Ele_Emissions_2040 = data_results['vEmiCO2CE'][(data_results['vEmiCO2CE'].sYear=='y2040') & (data_results['vEmiCO2CE'].sCE.isin(data_input['sCE_Ele'].sCE_Ele))].vEmiCO2CE.sum()*1e-3\n", + "CE_Ele_Emissions_2045 = data_results['vEmiCO2CE'][(data_results['vEmiCO2CE'].sYear=='y2045') & (data_results['vEmiCO2CE'].sCE.isin(data_input['sCE_Ele'].sCE_Ele))].vEmiCO2CE.sum()*1e-3\n", + "CE_Ele_Emissions_2050 = data_results['vEmiCO2CE'][(data_results['vEmiCO2CE'].sYear=='y2050') & (data_results['vEmiCO2CE'].sCE.isin(data_input['sCE_Ele'].sCE_Ele))].vEmiCO2CE.sum()*1e-3\n", + "\n", + "#Graph the emissions of the electricity sector\n", + "emissions = [CE_Ele_Emissions_2020, CE_Ele_Emissions_2025, CE_Ele_Emissions_2030, CE_Ele_Emissions_2035, CE_Ele_Emissions_2040, CE_Ele_Emissions_2045, CE_Ele_Emissions_2050]\n", + "technologies = data_results['vEmiCO2CE'][(data_results['vEmiCO2CE'].sCE.isin(data_input['sCE_Ele'].sCE_Ele))].groupby(['sCE','sYear']).vEmiCO2CE.sum()*1e-3\n", + "\n", + "# Preserve only the elements in technologies different from 0\n", + "#technologies = technologies[technologies != 0]\n", + "\n", + "axs[0, 1].plot(years, emissions, label='Total Emissions Electrity Generation', color='black', linewidth=1, marker='o')\n", + "axs[0, 1].plot(years,data_input['pEmiCO2CapEle'].pEmiCO2CapEle, label='CO2 Cap Electricity Generation (pEmiCO2CapEle)', color='red', linewidth=1, linestyle='dashed')\n", + "# CE TECHS with emissions of co2\n", + "# sCEIMCOTRA\n", + "# sCEIMCOIGCC\n", + "# sCEIMCOSCPC\n", + "# sCEIMCOSCCCS\n", + "# sCESLDWAST\n", + "# sCECCGTTRA\n", + "# sCECCGTCCS\n", + "# sCEOCGTTRA\n", + "# sCEOCGTCCS\n", + "# sCEFUOITRA\n", + "# sCECOGENINDNG\n", + "# sCECOGENOTHNG\n", + "\n", + "# Detect the technologies that are in the df that are different from 0\n", + "#technologies = technologies.unstack().fillna(0)\n", + "\n", + "# Plot the technologies\n", + "axs[0, 1].bar(years, technologies['sCEIMCOTRA'], label='IMCOTRA', color='blue')\n", + "axs[0, 1].bar(years, technologies['sCEIMCOIGCC'], label='IMCOIGCC', color='red', bottom=technologies['sCEIMCOTRA'])\n", + "axs[0, 1].bar(years, technologies['sCEIMCOSCPC'], label='IMCOSCPC', color='green', bottom=[sum(x) for x in zip(technologies['sCEIMCOTRA'], technologies['sCEIMCOIGCC'])])\n", + "axs[0, 1].bar(years, technologies['sCEIMCOSCCCS'], label='IMCOSCCCS', color='orange', bottom=[sum(x) for x in zip(technologies['sCEIMCOTRA'], technologies['sCEIMCOIGCC'], technologies['sCEIMCOSCPC'])])\n", + "axs[0, 1].bar(years, technologies['sCESLDWAST'], label='SLDWAST', color='brown', bottom=[sum(x) for x in zip(technologies['sCEIMCOTRA'], technologies['sCEIMCOIGCC'], technologies['sCEIMCOSCPC'], technologies['sCEIMCOSCCCS'])])\n", + "axs[0, 1].bar(years, technologies['sCECCGTTRA'], label='CCGTTRA', color='purple', bottom=[sum(x) for x in zip(technologies['sCEIMCOTRA'], technologies['sCEIMCOIGCC'], technologies['sCEIMCOSCPC'], technologies['sCEIMCOSCCCS'], technologies['sCESLDWAST'])])\n", + "axs[0, 1].bar(years, technologies['sCECCGTCCS'], label='CCGTCCS', color='yellow', bottom=[sum(x) for x in zip(technologies['sCEIMCOTRA'], technologies['sCEIMCOIGCC'], technologies['sCEIMCOSCPC'], technologies['sCEIMCOSCCCS'], technologies['sCESLDWAST'], technologies['sCECCGTTRA'])])\n", + "axs[0, 1].bar(years, technologies['sCEOCGTTRA'], label='OCGTTRA', color='pink', bottom=[sum(x) for x in zip(technologies['sCEIMCOTRA'], technologies['sCEIMCOIGCC'], technologies['sCEIMCOSCPC'], technologies['sCEIMCOSCCCS'], technologies['sCESLDWAST'], technologies['sCECCGTTRA'], technologies['sCECCGTCCS'])])\n", + "axs[0, 1].bar(years, technologies['sCEOCGTCCS'], label='OCGTCCS', color='grey', bottom=[sum(x) for x in zip(technologies['sCEIMCOTRA'], technologies['sCEIMCOIGCC'], technologies['sCEIMCOSCPC'], technologies['sCEIMCOSCCCS'], technologies['sCESLDWAST'], technologies['sCECCGTTRA'], technologies['sCECCGTCCS'], technologies['sCEOCGTTRA'])])\n", + "axs[0, 1].bar(years, technologies['sCEFUOITRA'], label='FUOITRA', color='cyan', bottom=[sum(x) for x in zip(technologies['sCEIMCOTRA'], technologies['sCEIMCOIGCC'], technologies['sCEIMCOSCPC'], technologies['sCEIMCOSCCCS'], technologies['sCESLDWAST'], technologies['sCECCGTTRA'], technologies['sCECCGTCCS'], technologies['sCEOCGTTRA'], technologies['sCEOCGTCCS'])])\n", + "axs[0, 1].bar(years, technologies['sCECOGENINDNG'], label='COGENINDNG', color='magenta', bottom=[sum(x) for x in zip(technologies['sCEIMCOTRA'], technologies['sCEIMCOIGCC'], technologies['sCEIMCOSCPC'], technologies['sCEIMCOSCCCS'], technologies['sCESLDWAST'], technologies['sCECCGTTRA'], technologies['sCECCGTCCS'], technologies['sCEOCGTTRA'], technologies['sCEOCGTCCS'], technologies['sCEFUOITRA'])])\n", + "axs[0, 1].bar(years, technologies['sCECOGENOTHNG'], label='COGENOTHNG', color='black', bottom=[sum(x) for x in zip(technologies['sCEIMCOTRA'], technologies['sCEIMCOIGCC'], technologies['sCEIMCOSCPC'], technologies['sCEIMCOSCCCS'], technologies['sCESLDWAST'], technologies['sCECCGTTRA'], technologies['sCECCGTCCS'], technologies['sCEOCGTTRA'], technologies['sCEOCGTCCS'], technologies['sCEFUOITRA'], technologies['sCECOGENINDNG'])])\n", + " \n", + "\n", + "# Add a title and labels for the second subplot\n", + "axs[0, 1].set_title('CO2 Emissions (vEmiCO2CE) of the Electricity Sector')\n", + "axs[0, 1].set_xlabel('Year')\n", + "axs[0, 1].set_ylabel('[MtCO2]')\n", + "axs[0, 1].legend()\n", + "axs[0, 1].legend(loc='center left', bbox_to_anchor=(0, -0.5))\n", + " #reduce the size of the legend of the subplot\n", + "\n", + "\n", + "# Third subplot\n", + "CE_Ref_Emissions_2020 = data_results['vEmiCO2CE'][(data_results['vEmiCO2CE'].sYear=='y2020') & (data_results['vEmiCO2CE'].sCE.isin(data_input['sCE_Ref'].sCE_Ref))].vEmiCO2CE.sum()*1e-3\n", + "CE_Ref_Emissions_2025 = data_results['vEmiCO2CE'][(data_results['vEmiCO2CE'].sYear=='y2025') & (data_results['vEmiCO2CE'].sCE.isin(data_input['sCE_Ref'].sCE_Ref))].vEmiCO2CE.sum()*1e-3\n", + "CE_Ref_Emissions_2030 = data_results['vEmiCO2CE'][(data_results['vEmiCO2CE'].sYear=='y2030') & (data_results['vEmiCO2CE'].sCE.isin(data_input['sCE_Ref'].sCE_Ref))].vEmiCO2CE.sum()*1e-3\n", + "CE_Ref_Emissions_2035 = data_results['vEmiCO2CE'][(data_results['vEmiCO2CE'].sYear=='y2035') & (data_results['vEmiCO2CE'].sCE.isin(data_input['sCE_Ref'].sCE_Ref))].vEmiCO2CE.sum()*1e-3\n", + "CE_Ref_Emissions_2040 = data_results['vEmiCO2CE'][(data_results['vEmiCO2CE'].sYear=='y2040') & (data_results['vEmiCO2CE'].sCE.isin(data_input['sCE_Ref'].sCE_Ref))].vEmiCO2CE.sum()*1e-3\n", + "CE_Ref_Emissions_2045 = data_results['vEmiCO2CE'][(data_results['vEmiCO2CE'].sYear=='y2045') & (data_results['vEmiCO2CE'].sCE.isin(data_input['sCE_Ref'].sCE_Ref))].vEmiCO2CE.sum()*1e-3\n", + "CE_Ref_Emissions_2050 = data_results['vEmiCO2CE'][(data_results['vEmiCO2CE'].sYear=='y2050') & (data_results['vEmiCO2CE'].sCE.isin(data_input['sCE_Ref'].sCE_Ref))].vEmiCO2CE.sum()*1e-3\n", + "\n", + "#Graph the emissions of the electricity sector\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "emissions = [CE_Ref_Emissions_2020, CE_Ref_Emissions_2025, CE_Ref_Emissions_2030, CE_Ref_Emissions_2035, CE_Ref_Emissions_2040, CE_Ref_Emissions_2045, CE_Ref_Emissions_2050]\n", + "technologies = data_results['vEmiCO2CE'][(data_results['vEmiCO2CE'].sCE.isin(data_input['sCE_Ref'].sCE_Ref))].groupby(['sCE','sYear']).vEmiCO2CE.sum()*1e-3\n", + "axs[1,0].plot(years, emissions, label='Total Refinery processes Emissions', color='black', linestyle='dashed', linewidth=1, marker='o')\n", + "axs[1,0].plot(years,data_input['pEmiCO2CapRef'].pEmiCO2CapRef, label='Refinery processes Cap (pEmiCO2CapRef)', color='red', linestyle='solid', linewidth=1, marker='o')\n", + "\n", + "# Add a bar stack plot with the emissions of each CE for each year\n", + "axs[1,0].bar(years, technologies.sCEBIODIEPP, label='Biodiesel Production Plant', color='purple')\n", + "axs[1,0].bar(years, technologies.sCEBIOETHPP, label='Bioethanol Production Plant', color='brown', bottom=technologies.sCEBIODIEPP)\n", + "axs[1,0].bar(years, technologies.sCEREFINVHIC, label='Refinery Very High Complexity', color='orange', bottom=[sum(x) for x in zip(technologies.sCEBIODIEPP, technologies.sCEBIOETHPP)])\n", + "axs[1,0].bar(years, technologies.sCEREFINHIGC, label='Refinery High Complexity', color='green', bottom=[sum(x) for x in zip(technologies.sCEBIODIEPP, technologies.sCEBIOETHPP, technologies.sCEREFINVHIC)])\n", + "axs[1,0].bar(years, technologies.sCEREFINLOWC, label='Refinery Low Complexity', color='red', bottom=[sum(x) for x in zip(technologies.sCEBIODIEPP, technologies.sCEBIOETHPP, technologies.sCEREFINVHIC, technologies.sCEREFINHIGC)])\n", + "\n", + "# Add a title and labels for the third subplot\n", + "axs[1,0].set_title('CO2 emissions of the Refinery Techs')\n", + "axs[1,0].set_xlabel('Year')\n", + "axs[1,0].set_ylabel('[MtCO2 above pEmiCO2CapRef]')\n", + "axs[1,0].legend()\n", + "axs[1,0].legend(loc='center left', bbox_to_anchor=(0, -0.4))\n", + "\n", + "# Fourth subplot\n", + "# Graph in other bar stack plot vEmiCO2CapExc vEmiNOxCapExc vEmiSOxCapExc vEmiPM25CapExc\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "\n", + "axs[1,1].bar(years, vEmiCO2CapExc, label='CO2 Total emissions over pEmiCO2Cap (CE TE ST) (vEmiCO2CapExc)', color='blue')\n", + "axs[1,1].bar(years, vEmiNOxCapExc, label='NOx Total emissions over pEmiNOxCap (CE ST) (vEmiNOxCapExc)', color='red', bottom=vEmiCO2CapExc)\n", + "axs[1,1].bar(years, vEmiSOxCapExc, label='SOx Total emissions over pEmiSOxCap (vEmiSOxCapExc)', color='green', bottom=[sum(x) for x in zip(vEmiCO2CapExc, vEmiNOxCapExc)])\n", + "axs[1,1].bar(years, vEmiPM25CapExc, label='PM2.5 Total emissions over pEmiPM25Cap (vEmiPM25CapExc)', color='orange', bottom=[sum(x) for x in zip(vEmiCO2CapExc, vEmiNOxCapExc, vEmiSOxCapExc)])\n", + "\n", + "# Add a title and labels for the fourth subplot\n", + "axs[1,1].set_title('Excess of Emissions regarding Emission Cap')\n", + "axs[1,1].set_xlabel('Year')\n", + "axs[1,1].set_ylabel('[Mt]')\n", + "axs[1,1].legend()\n", + "axs[1,1].legend(loc='center left', bbox_to_anchor=(0, -0.3))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "EMISSIONS ACCOUNTING" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "CO2" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "import seaborn as sns\n", + "\n", + "vEmiCO2ST_HEATMAP_2020_TRA = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSTRA')) & (data_results['vEmiCO2ST'].sYear=='y2020')]\n", + "vEmiCO2ST_HEATMAP_2025_TRA = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSTRA')) & (data_results['vEmiCO2ST'].sYear=='y2025')]\n", + "vEmiCO2ST_HEATMAP_2030_TRA = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSTRA')) & (data_results['vEmiCO2ST'].sYear=='y2030')]\n", + "vEmiCO2ST_HEATMAP_2035_TRA = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSTRA')) & (data_results['vEmiCO2ST'].sYear=='y2035')]\n", + "vEmiCO2ST_HEATMAP_2040_TRA = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSTRA')) & (data_results['vEmiCO2ST'].sYear=='y2040')]\n", + "vEmiCO2ST_HEATMAP_2045_TRA = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSTRA')) & (data_results['vEmiCO2ST'].sYear=='y2045')]\n", + "vEmiCO2ST_HEATMAP_2050_TRA = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSTRA')) & (data_results['vEmiCO2ST'].sYear=='y2050')]\n", + "\n", + "vEmiCO2ST_HEATMAP_2020_RES = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSOTH_RES')) & (data_results['vEmiCO2ST'].sYear=='y2020')]\n", + "vEmiCO2ST_HEATMAP_2025_RES = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSOTH_RES')) & (data_results['vEmiCO2ST'].sYear=='y2025')]\n", + "vEmiCO2ST_HEATMAP_2030_RES = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSOTH_RES')) & (data_results['vEmiCO2ST'].sYear=='y2030')]\n", + "vEmiCO2ST_HEATMAP_2035_RES = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSOTH_RES')) & (data_results['vEmiCO2ST'].sYear=='y2035')]\n", + "vEmiCO2ST_HEATMAP_2040_RES = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSOTH_RES')) & (data_results['vEmiCO2ST'].sYear=='y2040')]\n", + "vEmiCO2ST_HEATMAP_2045_RES = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSOTH_RES')) & (data_results['vEmiCO2ST'].sYear=='y2045')]\n", + "vEmiCO2ST_HEATMAP_2050_RES = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSOTH_RES')) & (data_results['vEmiCO2ST'].sYear=='y2050')]\n", + "\n", + "vEmiCO2ST_HEATMAP_2020_IND = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSIND')) & (data_results['vEmiCO2ST'].sYear=='y2020')]\n", + "vEmiCO2ST_HEATMAP_2025_IND = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSIND')) & (data_results['vEmiCO2ST'].sYear=='y2025')]\n", + "vEmiCO2ST_HEATMAP_2030_IND = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSIND')) & (data_results['vEmiCO2ST'].sYear=='y2030')]\n", + "vEmiCO2ST_HEATMAP_2035_IND = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSIND')) & (data_results['vEmiCO2ST'].sYear=='y2035')]\n", + "vEmiCO2ST_HEATMAP_2040_IND = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSIND')) & (data_results['vEmiCO2ST'].sYear=='y2040')]\n", + "vEmiCO2ST_HEATMAP_2045_IND = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSIND')) & (data_results['vEmiCO2ST'].sYear=='y2045')]\n", + "vEmiCO2ST_HEATMAP_2050_IND = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSIND')) & (data_results['vEmiCO2ST'].sYear=='y2050')]\n", + "\n", + "vEmiCO2CE_HEATMAP_2020 = data_results['vEmiCO2CE'][data_results['vEmiCO2CE'].sYear=='y2020']\n", + "vEmiCO2CE_HEATMAP_2025 = data_results['vEmiCO2CE'][data_results['vEmiCO2CE'].sYear=='y2025']\n", + "vEmiCO2CE_HEATMAP_2030 = data_results['vEmiCO2CE'][data_results['vEmiCO2CE'].sYear=='y2030']\n", + "vEmiCO2CE_HEATMAP_2035 = data_results['vEmiCO2CE'][data_results['vEmiCO2CE'].sYear=='y2035']\n", + "vEmiCO2CE_HEATMAP_2040 = data_results['vEmiCO2CE'][data_results['vEmiCO2CE'].sYear=='y2040']\n", + "vEmiCO2CE_HEATMAP_2045 = data_results['vEmiCO2CE'][data_results['vEmiCO2CE'].sYear=='y2045']\n", + "vEmiCO2CE_HEATMAP_2050 = data_results['vEmiCO2CE'][data_results['vEmiCO2CE'].sYear=='y2050']\n", + "\n", + "vEmiCO2TE_HEATMAP_2020 = data_results['vEmiCO2TE'][data_results['vEmiCO2TE'].sYear=='y2020']\n", + "vEmiCO2TE_HEATMAP_2025 = data_results['vEmiCO2TE'][data_results['vEmiCO2TE'].sYear=='y2025']\n", + "vEmiCO2TE_HEATMAP_2030 = data_results['vEmiCO2TE'][data_results['vEmiCO2TE'].sYear=='y2030']\n", + "vEmiCO2TE_HEATMAP_2035 = data_results['vEmiCO2TE'][data_results['vEmiCO2TE'].sYear=='y2035']\n", + "vEmiCO2TE_HEATMAP_2040 = data_results['vEmiCO2TE'][data_results['vEmiCO2TE'].sYear=='y2040']\n", + "vEmiCO2TE_HEATMAP_2045 = data_results['vEmiCO2TE'][data_results['vEmiCO2TE'].sYear=='y2045']\n", + "vEmiCO2TE_HEATMAP_2050 = data_results['vEmiCO2TE'][data_results['vEmiCO2TE'].sYear=='y2050']\n", + "\n", + "TotEmiSTRes_2020 = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSOTH')) & (data_results['vEmiCO2ST'].sYear=='y2020')].vEmiCO2ST.sum()*1e-3\n", + "TotEmiSTRes_2025 = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSOTH')) & (data_results['vEmiCO2ST'].sYear=='y2025')].vEmiCO2ST.sum()*1e-3\n", + "TotEmiSTRes_2030 = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSOTH')) & (data_results['vEmiCO2ST'].sYear=='y2030')].vEmiCO2ST.sum()*1e-3\n", + "TotEmiSTRes_2035 = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSOTH')) & (data_results['vEmiCO2ST'].sYear=='y2035')].vEmiCO2ST.sum()*1e-3\n", + "TotEmiSTRes_2040 = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSOTH')) & (data_results['vEmiCO2ST'].sYear=='y2040')].vEmiCO2ST.sum()*1e-3\n", + "TotEmiSTRes_2045 = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSOTH')) & (data_results['vEmiCO2ST'].sYear=='y2045')].vEmiCO2ST.sum()*1e-3\n", + "TotEmiSTRes_2050 = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSOTH')) & (data_results['vEmiCO2ST'].sYear=='y2050')].vEmiCO2ST.sum()*1e-3\n", + "\n", + "TotEmiSTInd_2020_TE = data_results['vEmiCO2STTE'][(data_results['vEmiCO2STTE'].sES.str.startswith('sST_DSIND')) & (data_results['vEmiCO2STTE'].sYear=='y2020')].vEmiCO2STTE.sum()*1e-3\n", + "TotEmiSTInd_2025_TE = data_results['vEmiCO2STTE'][(data_results['vEmiCO2STTE'].sES.str.startswith('sST_DSIND')) & (data_results['vEmiCO2STTE'].sYear=='y2025')].vEmiCO2STTE.sum()*1e-3\n", + "TotEmiSTInd_2030_TE = data_results['vEmiCO2STTE'][(data_results['vEmiCO2STTE'].sES.str.startswith('sST_DSIND')) & (data_results['vEmiCO2STTE'].sYear=='y2030')].vEmiCO2STTE.sum()*1e-3\n", + "TotEmiSTInd_2035_TE = data_results['vEmiCO2STTE'][(data_results['vEmiCO2STTE'].sES.str.startswith('sST_DSIND')) & (data_results['vEmiCO2STTE'].sYear=='y2035')].vEmiCO2STTE.sum()*1e-3\n", + "TotEmiSTInd_2040_TE = data_results['vEmiCO2STTE'][(data_results['vEmiCO2STTE'].sES.str.startswith('sST_DSIND')) & (data_results['vEmiCO2STTE'].sYear=='y2040')].vEmiCO2STTE.sum()*1e-3\n", + "TotEmiSTInd_2045_TE = data_results['vEmiCO2STTE'][(data_results['vEmiCO2STTE'].sES.str.startswith('sST_DSIND')) & (data_results['vEmiCO2STTE'].sYear=='y2045')].vEmiCO2STTE.sum()*1e-3\n", + "TotEmiSTInd_2050_TE = data_results['vEmiCO2STTE'][(data_results['vEmiCO2STTE'].sES.str.startswith('sST_DSIND')) & (data_results['vEmiCO2STTE'].sYear=='y2050')].vEmiCO2STTE.sum()*1e-3\n", + "\n", + "TotEmiSTInd_2020_PRO = data_results['vEmiCO2STPro'][(data_results['vEmiCO2STPro'].sST.str.startswith('sST_DSIND')) & (data_results['vEmiCO2STPro'].sYear=='y2020')].vEmiCO2STPro.sum()*1e-3\n", + "TotEmiSTInd_2025_PRO = data_results['vEmiCO2STPro'][(data_results['vEmiCO2STPro'].sST.str.startswith('sST_DSIND')) & (data_results['vEmiCO2STPro'].sYear=='y2025')].vEmiCO2STPro.sum()*1e-3\n", + "TotEmiSTInd_2030_PRO = data_results['vEmiCO2STPro'][(data_results['vEmiCO2STPro'].sST.str.startswith('sST_DSIND')) & (data_results['vEmiCO2STPro'].sYear=='y2030')].vEmiCO2STPro.sum()*1e-3\n", + "TotEmiSTInd_2035_PRO = data_results['vEmiCO2STPro'][(data_results['vEmiCO2STPro'].sST.str.startswith('sST_DSIND')) & (data_results['vEmiCO2STPro'].sYear=='y2035')].vEmiCO2STPro.sum()*1e-3\n", + "TotEmiSTInd_2040_PRO = data_results['vEmiCO2STPro'][(data_results['vEmiCO2STPro'].sST.str.startswith('sST_DSIND')) & (data_results['vEmiCO2STPro'].sYear=='y2040')].vEmiCO2STPro.sum()*1e-3\n", + "TotEmiSTInd_2045_PRO = data_results['vEmiCO2STPro'][(data_results['vEmiCO2STPro'].sST.str.startswith('sST_DSIND')) & (data_results['vEmiCO2STPro'].sYear=='y2045')].vEmiCO2STPro.sum()*1e-3\n", + "TotEmiSTInd_2050_PRO = data_results['vEmiCO2STPro'][(data_results['vEmiCO2STPro'].sST.str.startswith('sST_DSIND')) & (data_results['vEmiCO2STPro'].sYear=='y2050')].vEmiCO2STPro.sum()*1e-3\n", + "\n", + "TotEmiSTTra_2020 = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSTRA')) & (data_results['vEmiCO2ST'].sYear=='y2020')].vEmiCO2ST.sum()*1e-3\n", + "TotEmiSTTra_2025 = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSTRA')) & (data_results['vEmiCO2ST'].sYear=='y2025')].vEmiCO2ST.sum()*1e-3\n", + "TotEmiSTTra_2030 = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSTRA')) & (data_results['vEmiCO2ST'].sYear=='y2030')].vEmiCO2ST.sum()*1e-3\n", + "TotEmiSTTra_2035 = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSTRA')) & (data_results['vEmiCO2ST'].sYear=='y2035')].vEmiCO2ST.sum()*1e-3\n", + "TotEmiSTTra_2040 = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSTRA')) & (data_results['vEmiCO2ST'].sYear=='y2040')].vEmiCO2ST.sum()*1e-3\n", + "TotEmiSTTra_2045 = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSTRA')) & (data_results['vEmiCO2ST'].sYear=='y2045')].vEmiCO2ST.sum()*1e-3\n", + "TotEmiSTTra_2050 = data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSTRA')) & (data_results['vEmiCO2ST'].sYear=='y2050')].vEmiCO2ST.sum()*1e-3\n", + "\n", + "TotConsumption_RefineProduct = data_results['vQSTInTE'][data_results['vQSTInTE'].sTE.str.startswith('sTEOPDIE')].groupby(['sTE','sST']).vQSTInTE.sum()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(1095.7222222222222, 0.5, 'sTE')" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAF+gAAAJyCAYAAABJBl08AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdebRWZfk//vfzME9HBJXhozKIICjOqaQmBoo4J6KSKeBQpqiIZFp+TMpvlBOoYUiO5Qx+TFJTScV5Ts0R0CRHBgdATEHg/P5o8fw8MQh49OHA67XWXvHc+9rXfd37HFfnZh+uXaisrKwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACs4YrlLgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL4JGvQDAAAAAAAAAAAAAAAAAAAAAAAAAAAAALBW0KAfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIC1ggb9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACsFTToBwAAAAAAAAAAAAAAAAAAAAAAAAAAAABgraBBPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAawUN+gEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWCto0A8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAwFpBg34AAAAAAAAAAAAAAAAAAAAAAAAAAAAAANYKGvQDAAAAAAAAAAAAAAAAAAAAAAAAAAAAALBW0KAfgLXaU089lUGDBmXzzTdPo0aNsvHGG+eQQw7J5MmTl4h95ZVXstdee6Vx48Zp1qxZjjjiiMycObNKzKuvvprTTjstW2+9dZo0aZJWrVpln332ydNPP73U+d95550ccsghadq0aSoqKnLAAQfkn//859eyVgAA4JtXzj3H2WefnUKhsMRRv379r229AADAN6u69xzvvvtufvCDH6RTp05p0qRJmjZtmh122CHXXHNNKisrl8jpOQcAAKzZyrnn8JwDAADWfNW95/hv1113XQqFQho3brzU86uSEwAAqDnKuecYMGDAUp9zbLbZZtW2PgAAoPyqe98xderUpe4lCoVCbrzxxlXKCQAAwPLVLncBAFBOv/3tb/PII4+kb9++2XLLLTNt2rT87ne/y7bbbpvHH388W2yxRZLk7bffzne+852ss846+fWvf525c+fm/PPPzwsvvJAnn3wydevWTZJcfvnlueKKK9KnT58cf/zxmT17di677LLstNNOueuuu9KzZ8/S3HPnzs3uu++e2bNn52c/+1nq1KmTESNGZLfddstzzz2X5s2bl+WeAAAA1aece47Ffv/731f5he9atWp9M4sHAAC+dtW953j//ffz9ttv5+CDD87GG2+czz//PBMmTMiAAQMyadKk/PrXvy7N7TkHAACs+cq551jMcw4AAFhzVfee44vmzp2b0047LY0aNVrq3KuSEwAAqFnKuedIknr16uXyyy+vMrbOOutU7yIBAICy+rr2Hf369cvee+9dZaxbt25VPnvWAQAAUD0KlZWVleUuAgDK5dFHH832229f5S8Up0yZkq5du+bggw/OtddemyQ5/vjjc/XVV+fVV1/NxhtvnCT529/+lj322COXXXZZfvjDHyZJnnnmmXTq1KnKPwr94IMP0rlz53Ts2DEPP/xwafzcc8/NT3/60zz55JP51re+lSR59dVXs8UWW+S0005b6j84BQAAapZy7jnOPvvsDBs2LDNnzsx66633TSwXAAD4hlX3nmNZ9ttvv9x///2ZPXt2qRmm5xwAALDmK+eew3MOAABY832de47TTz89f/7zn7P99tvnz3/+c+bOnVvl/FfdxwAAAKu/cu45BgwYkHHjxi0xDgAArFmqe98xderUtGvXLuedd16GDh263Lk96wAAAKgexXIXAADl9O1vf3uJt31uuumm2XzzzfPKK6+Uxm655Zbsu+++pb+MTJKePXumY8eOufnmm0tj2223XZVGmUnSvHnz7LrrrlXyJcm4cePyrW99q9S0Jkk222yz9OjRo0pOAACg5irnnmOxysrKzJkzJ97TCQAAa57q3nMsS9u2bfPvf/878+fPL415zgEAAGu+cu45FvOcAwAA1lxf155jypQpGTFiRC688MLUrl17qXN/1X0MAACw+ivnnmOxhQsXZs6cOV9xJQAAwOrq6/z9qk8++WSpv0/1VXICAACwJA36AeC/VFZWZvr06VlvvfWSJO+8805mzJiR7bfffonYHXbYIc8+++yX5pw2bVopX5IsWrQo//jHP5aZ8/XXX8/HH3/8FVYBAACsrr6JPccXtW/fPuuss06aNGmSH/zgB5k+ffpXWwAAALBaq449x6effpr3338/U6dOzTXXXJOrrroq3bp1S4MGDZJ4zgEAAGuzb2LP8UWecwAAwNqlOvYcgwcPzu6775699957qXNUx+9rAQAANdM3sedY7N///ncqKiqyzjrrpFmzZjnhhBMyd+7c6lkIAACw2qqOfcewYcPSuHHj1K9fP9/61rdyzz33VDnvWQcAAED10aAfAP7Lddddl3feeSeHHnpokuS9995LkrRq1WqJ2FatWuXDDz/MvHnzlpnvoYceymOPPVbKl6R0zbJyJsm77777ldYBAACsnr6JPUeSrLvuuhk0aFAuu+yyjBs3Lsccc0xuuumm7LrrrpkzZ041rggAAFidVMee46KLLsr666+fdu3aZcCAAdlpp51y4403ls57zgEAAGuvb2LPkXjOAQAAa6uvuue44447cs899+TCCy9c5hxf9fe1AACAmuub2HMsvva0007LVVddlRtuuCH7779/Lr300uy1115ZsGBBNa4IAABY3XyVfUexWMyee+6Z8847L+PHj8+IESMyY8aM9O7dO3fccUfpOs86AAAAqk/tchcAAKuTV199NSeccEK6deuW/v37J0k+/fTTJEm9evWWiK9fv34pZmnnZ8yYke9///tp165dTjvttNL4iuYEAADWLN/UniNJTj755Cqf+/Tpkx122CGHH354Lr300px++unVsiYAAGD1UV17jn79+mX77bfPzJkzc/vtt2f69OlVnlt4zgEAAGunb2rPkXjOAQAAa6OvuueYP39+TjnllBx33HHp0qXLMuf5Kr+vBQAA1Fzf1J4jSYYPH17l82GHHZaOHTvm5z//ecaNG5fDDjusOpYEAACsZr7qvmPjjTfO3XffXSXmiCOOSJcuXXLqqadmn332WemcAAAALF+x3AUAwOpi2rRp2WeffbLOOutk3LhxqVWrVpKkQYMGSbLUt4J+9tlnVWK+6JNPPsm+++6bjz/+OLfddlsaN25cOreqOQEAgJrrm9xzLMv3v//9tGzZMn/729++ylIAAIDVUHXuOdq0aZOePXumX79+ue6669K+ffv07Nmz9EvcnnMAAMDa55vccyyL5xwAALDmqo49x4gRI/L+++9n2LBhy53Lcw4AAFj7fJN7jmU55ZRTUiwWPecAAIA1VHX/O/LFmjVrloEDB2bSpEl5++23qyUnAAAA/z8N+gEgyezZs9O7d+/MmjUrd911V1q3bl0616pVqyTJe++9t8R17733Xpo1a7bE20Lnz5+fgw46KP/4xz9y2223ZYsttqhyfvE1y8qZpEoNAABAzfZN7zmWZ6ONNsqHH364iisBAABWR9W95/hvBx98cN566608+OCDSTznAACAtc03vedYHs85AABgzVMde47Zs2fnnHPOybHHHps5c+Zk6tSpmTp1aubOnZvKyspMnTo1M2bMWKmcAADAmuGb3nMsS4MGDdK8eXPPOQAAYA30df9+1UYbbZQkpf2EZx0AAADVp3a5CwCAcvvss8+y3377ZfLkyfnb3/6WLl26VDn/P//zP1l//fXz9NNPL3Htk08+ma233rrK2KJFi3LkkUfm3nvvzc0335zddtttieuKxWK6du261JxPPPFE2rdvnyZNmny1hQEAAKuFcuw5lmXxL35vs802q7QWAABg9VPde46l+fTTT5P855fGE885AABgbVKOPceyeM4BAABrnurac3z00UeZO3duzj333Jx77rlLxLZr1y4HHHBA/vznP1fLPgYAAKgZyrHnWJaPP/4477//ftZff/2vtCYAAGD18k38ftU///nPJCntJzzrAAAAqD7FchcAAOW0cOHCHHrooXnssccyduzYdOvWbalxffr0ye2335633nqrNHbvvfdm8uTJ6du3b5XYE088MTfddFMuvfTSHHTQQcuc++CDD85TTz1V5S86J02alPvuu2+JnAAAQM1Uzj3HzJkzlxj7/e9/n5kzZ2avvfZaxRUBAACrk+recyxtH5EkV1xxRQqFQrbddtvSmOccAACw5ivnnsNzDgAAWPNV555jgw02yK233rrEsfvuu6d+/fq59dZbc8YZZ6xUTgAAoGYr157js88+y8cff7zEPL/61a9SWVnpOQcAAKxBvonfr3rnnXdy5ZVXZsstt0yrVq1WOicAAADLV6isrKwsdxEAUC6DBw/ORRddlP322y+HHHLIEud/8IMfJEneeuutbLPNNmnatGlOPvnkzJ07N+edd1423HDDPPXUU6lXr16SZOTIkTnllFPSrVu3HH/88Uvk+973vpdGjRolST7++ONss802+fjjjzN06NDUqVMnF154YRYuXJjnnnuu9MZSAACg5irnnqNhw4Y59NBD07Vr19SvXz8PP/xwbrzxxmy11VZ55JFH0rBhw69x5QAAwDehuvccgwcPziOPPJK99torG2+8cT788MPccssteeqpp3LiiSfm4osvLuX2nAMAANZ85dxzeM4BAABrvurecyzNgAEDMm7cuMydO7fK+FfJCQAA1Azl2nNMnTo122yzTfr165fNNtssSXL33XfnzjvvzF577ZU77rgjxWKxmlcLAACUQ3XvOwYOHJjXX389PXr0SOvWrTN16tRcdtll+fjjj3P33Xene/fupdyedQAAAFQPDfoBWKt17949DzzwwDLPf/H/Jl966aUMGTIkDz/8cOrWrZt99tknF1xwQVq0aFGKGTBgQK655ppl5nvjjTfStm3b0ue33347p5xySu65554sWrQo3bt3z4gRI9KhQ4evtjAAAGC1UM49x7HHHptHH300b731Vj777LO0adMmffr0yc9//vM0adLkqy8OAAAou+rec0yYMCEXX3xx/v73v2fmzJmpX79+ttxyyxxzzDHp379/CoVClfyecwAAwJqtnHsOzzkAAGDNV917jqVZVoP+r5ITAACoGcq155g1a1ZOPPHEPP7443n33XezcOHCdOjQIYcffniGDh2aOnXqfPXFAQAAq4Xq3nfccMMNGT16dF555ZV89NFHadq0aXbdddeceeaZ2XbbbZfI71kHAADAV6dBPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa4ViuQsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBvggb9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACsFTToBwAAAAAAAAAAAABWSffu3dO9e/dyl7Fc06dPz8EHH5zmzZunUChk5MiRXzln27ZtM2DAgNLniRMnplAoZOLEiV8599ft6quvTqFQyNSpU8tdSpLk7LPPTqFQyPvvv1/uUgAAAAAAAAAAAAAAgLWEBv0AAAAAAAAAAAAArFVef/31/OhHP0r79u1Tv379VFRUZOedd85FF12UTz/9tNzlrXZefvnlnH322atNQ/eVdcopp+Tuu+/OGWeckT/96U/Za6+9yl3SGu3dd9/N2Wefneeee67cpVSxaNGi/PGPf8yOO+6YZs2apUmTJunYsWOOPPLIPP7440n+8+KFQqHwpcfVV19d3sUAAAAAAAAAAAAAAABfSe1yFwAAAAAAAAAAAAAA35Q77rgjffv2Tb169XLkkUdmiy22yPz58/Pwww/nJz/5SV566aWMGTOm3GWuVl5++eUMGzYs3bt3T9u2baucu+eee8pT1Eq47777csABB2To0KHVlnPSpEkpFovVlm9N8u6772bYsGFp27Zttt5663KXU3LSSSdl1KhROeCAA3L44Yendu3amTRpUv7617+mffv22WmnnTJy5MjMnTu3dM2dd96ZG264ISNGjMh6661XGv/2t79djiUAAAAAAAAAAAAAAADVRIN+AAAAAAAAAAAAANYKb7zxRg477LC0adMm9913X1q1alU6d8IJJ+S1117LHXfcUcYKa566deuWu4QvNWPGjDRt2rRac9arV69a862IRYsWZf78+alfv/43PndNN3369Fx66aU59thjl3gBx8iRIzNz5swkyYEHHljl3LRp03LDDTfkwAMPXOLlFAAAAAAAAAAAAAAAQM1VLHcBAAAAAAAAAAAAAPBNOPfcczN37txcccUVVZrzL9ahQ4ecfPLJpc8LFizIr371q2yyySapV69e2rZtm5/97GeZN29elevatm2bfffdNw8//HB22GGH1K9fP+3bt88f//jHKnGff/55hg0blk033TT169dP8+bNs8suu2TChAmlmO7du6d79+5L1DZgwIAqDcKnTp2aQqGQ888/P6NGjUr79u3TsGHD7LnnnnnrrbdSWVmZX/3qV9lwww3ToEGDHHDAAfnwww+XWvc999yTrbfeOvXr10+XLl3yf//3f6WYq6++On379k2S7L777ikUCikUCpk4ceIy650xY0aOPvrotGjRIvXr189WW22Va665pkrMF+sfM2ZM6R5/61vfylNPPbXE+pfmn//8Z/r27ZtmzZqlYcOG2Wmnnaq8YOHqq69OoVBIZWVlRo0aVap9eT755JOceuqp2WijjVKvXr106tQp559/fiorK5e4dwMGDFihOr/o7LPPTqFQyKuvvppDDjkkFRUVad68eU4++eR89tlnVWILhUIGDRqU6667Lptvvnnq1auXu+66K0ny7LPPpnfv3qmoqEjjxo3To0ePPP7440vM99JLL+W73/1uGjRokA033DDnnHNOFi1atERcoVDI2WefvcT40tY5a9asnHLKKWnbtm3q1auXDTfcMEceeWTef//9TJw4Md/61reSJAMHDizd86uvvvpL783777+/3Huy2267ZauttlrqtZ06dUqvXr2WmfuNN95IZWVldt5556WufYMNNvjS+gAAAAAAAAAAAAAAgDVH7XIXAAAAAAAAAAAAAADfhL/85S9p3759vv3tb69Q/DHHHJNrrrkmBx98cE499dQ88cQTGT58eF555ZXceuutVWJfe+21HHzwwTn66KPTv3//XHnllRkwYEC22267bL755kn+05x9+PDhOeaYY7LDDjtkzpw5efrpp/P3v/89e+yxxyqt6brrrsv8+fNz4okn5sMPP8y5556bQw45JN/97nczceLE/PSnP81rr72WSy65JEOHDs2VV15Z5fopU6bk0EMPzXHHHZf+/fvnqquuSt++fXPXXXdljz32yHe+852cdNJJufjii/Ozn/0snTt3TpLS//63Tz/9NN27d89rr72WQYMGpV27dhk7dmwGDBiQWbNmVXkBQpJcf/31+fjjj/OjH/0ohUIh5557bg466KD885//TJ06dZa57unTp+fb3/52/v3vf+ekk05K8+bNc80112T//ffPuHHj8r3vfS/f+c538qc//SlHHHFE9thjjxx55JHLvZeVlZXZf//9c//99+foo4/O1ltvnbvvvjs/+clP8s4772TEiBEr8iVZIYccckjatm2b4cOH5/HHH8/FF1+cjz76aImXOtx33325+eabM2jQoKy33npp27ZtXnrppey6666pqKjIaaedljp16uSyyy5L9+7d88ADD2THHXdMkkybNi277757FixYkNNPPz2NGjXKmDFj0qBBg1Wue+7cudl1113zyiuv5Kijjsq2226b999/P+PHj8/bb7+dzp0755e//GXOOuus/PCHP8yuu+6aJCv039yX3ZMjjjgixx57bF588cVsscUWpeueeuqpTJ48OWeeeeYyc7dp0yZJMnbs2PTt2zcNGzZc5XsAAAAAAAAAAAAAAADUfBr0AwAAAAAAAAAAALDGmzNnTt55550ccMABKxT//PPP55prrskxxxyTP/zhD0mS448/PhtssEHOP//83H///dl9991L8ZMmTcqDDz5Yakh+yCGHZKONNspVV12V888/P0lyxx13ZO+9986YMWOqbV3vvPNOpkyZknXWWSdJsnDhwgwfPjyffvppnn766dSu/Z9fF545c2auu+66/P73v0+9evVK10+ePDm33HJLDjrooCTJ0Ucfnc022yw//elPs8cee6R9+/bZddddc/HFF2ePPfZI9+7dl1vPmDFj8sorr+Taa6/N4YcfniQ57rjjsttuu+XMM8/MUUcdlSZNmpTi33zzzUyZMiXrrrtukqRTp0454IADcvfdd2ffffdd5jy/+c1vMn369Dz00EPZZZddkiTHHntsttxyywwZMiQHHHBA2rdvn/bt2+eII45Ix44d84Mf/GC5tY8fPz733XdfzjnnnPz85z9Pkpxwwgnp27dvLrroogwaNCibbLLJcnOsqHbt2uW2224rzVFRUZFLL700Q4cOzZZbblmKmzRpUl544YV06dKlNPa9730vn3/+eR5++OG0b98+SXLkkUemU6dOOe200/LAAw8kSX77299m5syZeeKJJ7LDDjskSfr3759NN910les+77zz8uKLL+b//u//8r3vfa80fuaZZ6aysjKFQiG9e/fOWWedlW7dun3pPV+Ze9K3b9+ceOKJufbaa/Ob3/ymdN21116bRo0alb6Hl6ZVq1Y58sgj88c//jEbbrhhunfvnp133jn77LNPNttss1W4EwAAAAAAAAAAAAAAQE1WLHcBAAAAAAAAAAAAAPB1mzNnTpJUaQ6/PHfeeWeSZMiQIVXGTz311CT/abb/RV26dCk150+S9ddfP506dco///nP0ljTpk3z0ksvZcqUKSu/gGXo27dvqTl/kuy4445Jkh/84Ael5vyLx+fPn5933nmnyvWtW7eu0mi9oqIiRx55ZJ599tlMmzZtpeu5884707Jly/Tr1680VqdOnZx00kmZO3duqXn8YoceemipOX+S0j384n1b1jw77LBDqTl/kjRu3Dg//OEPM3Xq1Lz88surVHutWrVy0kknVRk/9dRTU1lZmb/+9a8rnXNZTjjhhCqfTzzxxFINX7TbbrtVac6/cOHC3HPPPTnwwANLzfmT/zSg//73v5+HH3649L1+5513Zqeddio150/+8325+MUJq+KWW27JVlttVeV7ZrFCobDKeZMvvyfrrLNODjjggNxwww2prKxM8p/7cdNNN+XAAw9Mo0aNlpv/qquuyu9+97u0a9cut956a4YOHZrOnTunR48eS/x3AQAAAAAAAAAAAAAArNk06AcAAAAAAAAAAABgjVdRUZEk+fjjj1co/l//+leKxWI6dOhQZbxly5Zp2rRp/vWvf1UZ33jjjZfIse666+ajjz4qff7lL3+ZWbNmpWPHjunatWt+8pOf5B//+MfKLmW58y5u1r/RRhstdfyL9SRJhw4dlmis3rFjxyTJ1KlTV7qef/3rX9l0001TLFb9NeXOnTuXzi+v/sXN+v+7zqXN06lTpyXGlzXPivjXv/6V1q1bL/ESh6+Sc1k23XTTKp832WSTFIvFJe55u3btqnyeOXNm/v3vfy9z7YsWLcpbb71Vqve/50my1GtX1Ouvv54ttthila9fnhW5J0ceeWTefPPNPPTQQ0mSv/3tb5k+fXqOOOKIL81fLBZzwgkn5Jlnnsn777+f2267Lb179859992Xww47rFrXAgAAAAAAAAAAAAAArN406AcAAAAAAAAAAABgjVdRUZHWrVvnxRdfXKnr/rt5/bLUqlVrqeOVlZWlP3/nO9/J66+/niuvvDJbbLFFLr/88my77ba5/PLLv3S+hQsXrtS8K1LP6qCm1Pl1W9bXvUGDBt9wJVUt6/vum7C0e9KrV6+0aNEi1157bZLk2muvTcuWLdOzZ8+Vyt28efPsv//+ufPOO7Pbbrvl4YcfrtYXMAAAAAAAAAAAAAAAAKs3DfoBAAAAAAAAAAAAWCvsu+++ef311/PYY499aWybNm2yaNGiTJkypcr49OnTM2vWrLRp02aVamjWrFkGDhyYG264IW+99Va23HLLnH322aXz6667bmbNmrXEdV9X8/DXXnttiWb4kydPTpK0bds2yYq/pCD5z32bMmVKFi1aVGX81VdfLZ2vDm3atMmkSZOWGP8q87Rp0ybvvvtuPv7442rLuSz//X312muvZdGiRaV7vizrr79+GjZsuMy1F4vFbLTRRqV6/3ueJEu9dmnfd/Pnz897771XZWyTTTb50pdcrMz3yxetyD2pVatWvv/972fcuHH56KOP8uc//zn9+vVb5oseVsT222+fJEusFQAAAAAAAAAAAAAAWHNp0A8AAAAAAAAAAADAWuG0005Lo0aNcswxx2T69OlLnH/99ddz0UUXJUn23nvvJMnIkSOrxFx44YVJkn322Wel5//ggw+qfG7cuHE6dOiQefPmlcY22WSTvPrqq5k5c2Zp7Pnnn88jjzyy0vOtiHfffTe33npr6fOcOXPyxz/+MVtvvXVatmyZJGnUqFGSLPXFAf9t7733zrRp03LTTTeVxhYsWJBLLrkkjRs3zm677VYtde+999558sknq7xs4ZNPPsmYMWPStm3bdOnSZZVyLly4ML/73e+qjI8YMSKFQiG9e/f+ynUvNmrUqCqfL7nkkiT50jlq1aqVPffcM7fddlumTp1aGp8+fXquv/767LLLLqmoqEjyn/U8/vjjefLJJ0txM2fOzHXXXbdE3k022SQPPvhglbExY8Zk4cKFVcb69OmT559/vsr3zGKLX/SwMt8vX7Si9+SII47IRx99lB/96EeZO3dufvCDH3xp7mnTpuXll19eYnz+/Pm59957UywW06FDh5WqFwAAAAAAAAAAAAAAqLlql7sAAAAAAAAAAAAAAPgmbLLJJrn++utz6KGHpnPnzjnyyCOzxRZbZP78+Xn00UczduzYDBgwIEmy1VZbpX///hkzZkxmzZqV3XbbLU8++WSuueaaHHjggdl9991Xev4uXbqke/fu2W677dKsWbM8/fTTGTduXAYNGlSKOeqoo3LhhRemV69eOfroozNjxoyMHj06m2++eebMmVNdt6KkY8eOOfroo/PUU0+lRYsWufLKKzN9+vRcddVVpZitt946tWrVym9/+9vMnj079erVy3e/+91ssMEGS+T74Q9/mMsuuywDBgzIM888k7Zt22bcuHF55JFHMnLkyDRp0qRa6j799NNzww03pHfv3jnppJPSrFmzXHPNNXnjjTdyyy23pFgsrnTO/fbbL7vvvnt+/vOfZ+rUqdlqq61yzz335LbbbsvgwYOzySabVEvtSfLGG29k//33z1577ZXHHnss1157bb7//e9nq622+tJrzznnnEyYMCG77LJLjj/++NSuXTuXXXZZ5s2bl3PPPbcUd9ppp+VPf/pT9tprr5x88slp1KhRxowZkzZt2uQf//hHlZzHHHNMjjvuuPTp0yd77LFHnn/++dx9991Zb731qsT95Cc/ybhx49K3b98cddRR2W677fLhhx9m/PjxGT16dLbaaqtssskmadq0aUaPHp0mTZqkUaNG2XHHHdOuXbtquSfbbLNNtthii4wdOzadO3fOtttu+6X37O23384OO+yQ7373u+nRo0datmyZGTNm5IYbbsjzzz+fwYMHL7FWAAAAAAAAAAAAAABgzbXy//IEAAAAAAAAAAAAAGqo/fffP//4xz9y8MEH57bbbssJJ5yQ008/PVOnTs0FF1yQiy++uBR7+eWXZ9iwYXnqqacyePDg3HfffTnjjDNy4403rtLcJ510UqZOnZrhw4fnpJNOygMPPJBzzjknF1xwQSmmc+fO+eMf/5jZs2dnyJAhGT9+fP70pz+tUBPyVbHpppvmpptuyp133pnTTz89n3/+eW666ab06tWrFNOyZcuMHj06M2bMyNFHH51+/frl5ZdfXmq+Bg0aZOLEiTn88MNzzTXX5NRTT82HH36Yq666KieffHK11d2iRYs8+uij2WOPPXLJJZfkjDPOSN26dfOXv/wl3/ve91YpZ7FYzPjx4zN48ODcfvvtGTx4cF5++eWcd955ufDCC6ut9iS56aabUq9evZx++um54447MmjQoFxxxRUrdO3mm2+ehx56KFtssUWGDx+eYcOGpU2bNrn//vuz4447luJatWqV+++/P1tuuWV+85vfZOTIkTnyyCOX+nU49thj89Of/jQPPvhgTj311LzxxhuZMGFCGjVqVCWucePGeeihh/LjH/84d955Z0466aRceuml6dSpUzbccMMkSZ06dXLNNdekVq1aOe6449KvX7888MAD1XpPjjzyyCTJEUccsUL3rFOnThk5cmRq166dSy+9ND/60Y/y//7f/0vDhg3zhz/8odq/vgAAAAAAAAAAAAAAwOqtUFlZWVnuIgAAAAAAAAAAAACAb1bbtm2zxRZb5Pbbby93KWuNs88+O8OGDcvMmTOz3nrrlbucGuuiiy7KKaeckqlTp2bjjTcudzkAAAAAAAAAAAAAAEANUyx3AQAAAAAAAAAAAAAAsCIqKytzxRVXZLfddtOcHwAAAAAAAAAAAAAAWCW1y10AAAAAAAAAAAAAAAAszyeffJLx48fn/vvvzwsvvJDbbrut3CUBAAAAAAAAAAAAAAA1lAb9AAAAAAAAAAAAAACs1mbOnJnvf//7adq0aX72s59l//33L3dJAAAAAAAAAAAAAABADVWorKysLHcRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwdSuWuwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPgmaNAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMBaQYN+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAADWCrXLXQBf3a4HPFTtOVt12Kjac3407YNqz/npnLnVnrNWnTrVnrN23er/T23+p/OqPWftenWrPeeCefOrPWehWKj2nIsWLKz2nACsvJbtq/9nkGn/fKvac55x1w+rPefwvcZUe86aoqb8DLI2ql+vmL+N2zVJsschj+SzeYuqLbc9R/WqKXuOWnWqv86Fny+o9pz2HABrrvU2alXtOd9/671qz/m3AX+v9pw9r9622nPWFHUa1K/2nJ9/+lm151wb2XOs3XuOeZ98Wu05v46/Y7DnAGBlNN+wZbXn/ODtadWe84gTd6v2nH+65IFqz1lT1G/cqNpzfjb3k2rPuTay57DnqG72HACsDpq2XL/ac86aNrPac1J91ubfrSoUi9Wes3JR9e0L7DnsOarb17H2RQur/2d5ew6ANZs9x9ppdf/Z++u0Oq/9i3uOngc/VK17jtYd21RbrsXsOarX17HnKNauVe05KxdVVntOew6ANdvXsef4+INZ1Z5z4eefV3tOWB3Zd6y9+46vY8/xdeyxvw72HABrtnVaNK/2nLOnV//PILC2efgv1f/vmABYujvqdFrla/f5fFI1VlKzaNAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFDDFOpU/4vp1gY147WDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwFdUudwEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKycYu1CuUuokTToBwAAAAAAAAAAAAAAAAAAAAAAAAAAAACoYQp1iuUuoUbSoB8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAoIYp1i6Uu4QaSYN+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAaplBHg/5VUSx3AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArJxi7cIqHyvrnXfeyQ9+8IM0b948DRo0SNeuXfP000+XzldWVuass85Kq1at0qBBg/Ts2TNTpkypkuPDDz/M4YcfnoqKijRt2jRHH3105s6dWyXmH//4R3bdddfUr18/G220Uc4999wlahk7dmw222yz1K9fP127ds2dd965UmvRoB8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAgKX66KOPsvPOO6dOnTr561//mpdffjkXXHBB1l133VLMueeem4svvjijR4/OE088kUaNGqVXr1757LPPSjGHH354XnrppUyYMCG33357Hnzwwfzwhz8snZ8zZ0723HPPtGnTJs8880zOO++8nH322RkzZkwp5tFHH02/fv1y9NFH59lnn82BBx6YAw88MC+++OIKr6f2V7wfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8wwp1Ct/IPL/97W+z0UYb5aqrriqNtWvXrvTnysrKjBw5MmeeeWYOOOCAJMkf//jHtGjRIn/+859z2GGH5ZVXXsldd92Vp556Kttvv32S5JJLLsnee++d888/P61bt851112X+fPn58orr0zdunWz+eab57nnnsuFF15YauR/0UUXZa+99spPfvKTJMmvfvWrTJgwIb/73e8yevToFVpPsVruCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA35hi7cIqH/PmzcucOXOqHPPmzVvqPOPHj8/222+fvn37ZoMNNsg222yTP/zhD6Xzb7zxRqZNm5aePXuWxtZZZ53suOOOeeyxx5Ikjz32WJo2bVpqzp8kPXv2TLFYzBNPPFGK+c53vpO6deuWYnr16pVJkyblo48+KsV8cZ7FMYvnWaH7tsKRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACsFgq1Cqt8DB8+POuss06VY/jw4Uud55///Gd+//vfZ9NNN83dd9+dH//4xznppJNyzTXXJEmmTZuWJGnRokWV61q0aFE6N23atGywwQZVzteuXTvNmjWrErO0HF+cY1kxi8+viNorHAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwGqhWKuwyteeccYZGTJkSJWxevXqLTV20aJF2X777fPrX/86SbLNNtvkxRdfzOjRo9O/f/9VrqFciuUuAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAlVMoFlb5qFevXioqKqocy2rQ36pVq3Tp0qXKWOfOnfPmm28mSVq2bJkkmT59epWY6dOnl861bNkyM2bMqHJ+wYIF+fDDD6vELC3HF+dYVszi8ytCg34AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJZq5513zqRJk6qMTZ48OW3atEmStGvXLi1btsy9995bOj9nzpw88cQT6datW5KkW7dumTVrVp555plSzH333ZdFixZlxx13LMU8+OCD+fzzz0sxEyZMSKdOnbLuuuuWYr44z+KYxfOsCA36AQAAAAAAAAAAAAAAAAAAAAAAAAAAAABqmEKt4iofK+OUU07J448/nl//+td57bXXcv3112fMmDE54YQT/lNHoZDBgwfnnHPOyfjx4/PCCy/kyCOPTOvWrXPggQcmSTp37py99torxx57bJ588sk88sgjGTRoUA477LC0bt06SfL9738/devWzdFHH52XXnopN910Uy666KIMGTKkVMvJJ5+cu+66KxdccEFeffXVnH322Xn66acz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Jp9//nl69uxZit1ss82y8cYb57HHHkuSPPbYY+natWtatGhRiunVq1fmzJmTl156qRTzxRyLYxbnmD9/fp555pkqMcViMT179izFrCgN+gEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaphCobjKx/Dhw7POOutUOYYPH77UeXbcccdcffXVueuuu/L73/8+b7zxRnbdddd8/PHHmTZtWurWrZumTZtWuaZFixaZNm1akmTatGlVmvMvPr/43PJi5syZk08//TTvv/9+Fi5cuNSYxTlWVO2VigYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoEY744wzMmTIkCpj9erVW2ps7969S3/ecssts+OOO6ZNmza5+eab06BBg6+1zq9DsdwFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwkoqFVT7q1auXioqKKseyGvT/t6ZNm6Zjx4557bXX0rJly8yfPz+zZs2qEjN9+vS0bNkySdKyZctMnz59ifOLzy0vpqKiIg0aNMh6662XWrVqLTVmcY4VpUE/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEANUygWV/n4KubOnZvXX389rVq1ynbbbZc6derk3nvvLZ2fNGlS3nzzzXTr1i1J0q1bt7zwwguZMWNGKWbChAmpqKhIly5dSjFfzLE4ZnGOunXrZrvttqsSs2jRotx7772lmBVVe+WWCwAAAAAAAAAAAAAAAAAAAAAAAAAAAABAuRWKhW9knqFDh2a//fZLmzZt8u677+YXv/hFatWqlX79+mWdddbJ0UcfnSFDhqRZs2apqKjIiSeemG7dumWnnXZKkuy5557p0qVLjjjiiJx77rmZNm1azjzzzJxwwgmpV69ekuS4447L7373u5x22mk56qijct999+Xmm2/OHXfcUapjyJAh6d+/f7bffvvssMMOGTlyZD755JMMHDhwpdajQT8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQE1TKH4j07z99tvp169fPvjgg6y//vrZZZdd8vjjj2f99ddPkowYMSLFYjF9+vTJvHnz0qtXr1x66aWl62vVqpXbb789P/7xj9OtW7c0atQo/fv3zy9/+ctSTLt27XLHHXfklFNOyUUXXZQNN9wwl19+eXr16lWKOfTQQzNz5sycddZZmTZtWrbeeuvcddddadGixUqtR4N+AAAAAAAAAAAA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uGEGDhyYGTNmVIm7//77s++++2b99ddP/fr1s8kmm+TQQw/Ngw8+WCXuD3/4Q7baaqs0btw4TZs2zTbbbJPhw4eXzp999tkpFAo57rjjqlz33HPPpVAoZOrUqdVwJwEAAAAAAAAAAAAAAAAAAAAAAAAAAACANVahuOrHWqx2uQv4b0899VQWLlyYJHn00UfTp0+fTJo0KRUVFUmSBg0alGKvuuqq7LXXXlWub9q0aZKksrIyhx12WP72t7/lvPPOS48ePTJnzpyMGjUq3bt3z9ixY3PggQeWrquoqMikSZOyaNGiPP/88xk4cGDefffd3H333UmSSy+9NIMGDcoRRxyRm266KZtssklmz56d+++/P6ecckqeeeaZJMmVV16ZwYMH5+KLL85uu+2WefPm5R//+EdefPHFKnXWr18/V1xxRU499dRsuumm1XoPAQAAAAAAAAAAAAAAAAAAAAAAAAAAAIA1W2WhUO4SaqSyNugfN25chg0bltdeey0NGzbMNttsk9tuuy2NGjVKkjRr1ixJssEGG5Qa739R06ZN07Jly6XmvvnmmzNu3LiMHz8+++23X2l8zJgx+eCDD3LMMcdkjz32KM1VKBRKuVq3bp2TTjop//u//5tPP/00M2fOzODBgzN48OBceOGFVebZcsstc9JJJ5U+jx8/PoccckiOPvro0tjmm2++RH2dOnXKBhtskJ///Oe5+eabV+R2AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8R6FY7gpqpLLdtffeey/9+vXLUUcdlVdeeSUTJ07MQQcdlMrKymrJf/3116djx45VmvMvduqpp+aDDz7IhAkTlnl9gwYNsmjRoixYsCC33HJLPv/885x22mlLjS184e0QLVu2zOOPP55//etfX1rjb37zm9xyyy15+umnV2BFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/UZnCKh9rs7I26F+wYEEOOuigtG3bNl27ds3xxx+fxo0br3COfv36pXHjxlWON998M0kyefLkdO7ceanXLR6fPHnyUs9PmTIlo0ePzvbbb58mTZpk8uTJqaioSMuWLUsxt9xyS5V5X3jhhSTJL37xizRt2jRt27ZNp06dMmDAgNx8881ZtGjREvNsu+22OeSQQ/LTn/50hdc8b968zJkzp8qxaOH8Fb4eAAAAAAAAAAAAAAAAAAAA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ffbZ1c68+uqro6ioKBYsWJC9U1uF8847L/r16xfXXHNNnHvuudXObNq0aRx99NFx9NFHxxtvvBFTp06NG2+8MS688MIYOHBgHHvssTFkyJDsea6uDz/8MJo0abLRY3K581tjPp91fS6vvvrqePjhh+Oee+6pdAfriIh77rknRo0aFVdffXX23OYr84s/y6v62Z6rjb3/P//5z/j1r38dq1atyilz0qRJsffee1fa9rvf/S623XbbSJIkbrrpprjmmmvid7/7XU65N9xwwybvjpnL3auvvvrqmDhxYpxyyinxwAMPxCGHHBI33HBDjBgxIiI+uxP12LFj45e//GVOc7788stRXl6+0WN23XXXaufVx/XCJZdcEpdcckn069cvpk2bFk888UTcddddcdFFF0U6nY5rrrkmzjvvvLjuuuuqnXnzzTfHSSedVGnb53+2T5kyJX7/+9/Hsccem9OsdX2d+J///KfK7R9//HFcffXVcc0119TqemRD6vpz1CTzL3/5S53P8EU6h85RUzqHzhGhc+gcW/751DuqtiX3Dp1D5/g8naNu6Bw6R03pHDpHhM7REK+RnU+do6rnNdFYO0eE3tEYe4fOUb90Dp2jpnQOnSNC52iI18jOp85R1fOa0Dl0jsbUOSL0jvrWUHuHzrE+nSN3OofO0diukZ1PnaOq5zWhc+gcOsdndI660VA7R03m2BS9o/H1Dp1D52hs18jOp85R1fOa0Dl0Dp3jMzpH3dA5dI6aKoTOEaF3NMbe0ZivkXUOnaOq5zWhc+gcOsdndA4A2ELU18r/5E917lxU27sMPfHEE8nee++dNGvWLDnrrLOSDz74oEZz/uhHP0pOO+20jT5yUVpaWukOd/369Ut+/vOfZ5+/+eabSYsWLXLKbNasWfL8889vcP/zzz+fNGvWLKfMqrz66qvJkCFDkqKiouToo49O/vnPf+b0+meeeSY54YQTktatWye9evVKJk2aVKOvS31nftEX/3zWRPPmzZNFixZln69atSopLi6uk7uXvfXWW8m3vvWtpGnTpklpaWly0UUXJWvXrq1R1owZM5LBgwcnzZs3Tw4//PDkrrvuys66YMGCGmV+/etfT6688soN7p8wYULy9a9/PafMr371q8ncuXOzz7/4NZo9e3bStWvXnDJbtGiRvP7660mSfHaHxqKiouTFF1/M7n/z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/+L666+PTz75JA499NDYZ599csqq7t0bc7lb14Z8+OGHceutt8YNN9wQ8+bNy/tdMz9/d7+qvv41uatYfWT+9re/jSOOOKJOf7n95ptvxqGHHhovv/xyRERsu+228cc//jG+/vWv1zjz6aefjj322GODd31btWpV3H333fH973+/xu/xRZ988kn86le/ijPPPDPn1/7rX/+K6dOnx6JFiyIiolu3bnHYYYfFdtttV+N5brvttrj11luzmTvttFMMHz48hg0blnNWPs5nQ9GlS5d46623okmTJtG3b9/Yd999Y99994299tqrxr+Mb6znsz7OZYWPP/44HnzwwUp/hw444IBa3fmyLjOvueaaah136qmn5pxdH5566qkqv3/06dMn56zhw4dHx44dY8KECRERsXTp0th5552jY8eO8T//8z/x5z//OW688cY46qijqp3Zpk2bmDx5cs6/HN2YMWPGxJo1a2LSpEkR8dmdvPfaa69YsGBBNGvWLNauXRuzZs2Kvn371tl71sT8+fNj9913r9f81157LSI++7r36tWrRjn33ntvvP/++zFy5MjstksuuSQuvvjiWLt2bey3335x++23R5s2bepi7Bpr06ZNta67c7mzaX1kNm/ePF588cXsPzx80RtvvBE9e/aMlStXVjtT59g0nSN/mTrHhukcW941coTOUdf0jk3TOzZN59i9XvN1jvXpHPmnc9QNnUPn0DkaJp2jbukcm6ZzVI/esXu95jeW3qFz6Bwbo3PkL1Pn2DCdwzVydTmfOsfG6BzVo3PsXq/5jaVzROgdhdI7dI66oXPoHDpHw6Rz1C2dY9N0jurROXav13ydY306R/7pHXWjsfYOnUPnaMh0jrqlc2yazlE9Osfu9Zqvc6xP58g/naNuNNbOEaF3ROgdDZXOUbd0jk3TOapH59i9XvN1jvVtiZ0DABoaC/RvgS688MLs/ydJEuPHj48TTjgh2rZtW+m4cePG5Zw9ffr0uPXWW7MXr926dYsjjzwyDj/88JyzXnzxxTjkkEPi//7v/2KnnXaK2267LQ488MBYuXJlpNPpWLlyZcyYMSOGDBlS7cxRo0ZV67hc7tb1RY8//njccMMNceedd0bHjh1j6NChcdhhh9XqF2p1oT7u7lkfmUVFRbF48eIN3tG0Jg4//PBYsGBBnH/++dGkSZO44oor4tNPP4158+bVOPOLc7Zs2TLmz5+fLQdLliyJjh075vzL7XfffTfmzp0bJSUlMWDAgCgqKoo1a9bEtddeG7/85S9jzZo18d5779V47oaqvs5nXevSpUu17sr4j3/8I6fcf/7zn/GXv/wlZs+eHY899li8/fbb0bx58+jXr1/2F3V77rlntfMa8/ms63NZHf/+979j2223zWtmly5dNnlMKpWKN954ozZjRUTt7vJYH7p06RJTp07N/qy54oorYsqUKfHqq69GcXFxXHHFFTFjxox46qmnqp157bXXxtlnnx0HHnhgTJkypU7uKP3Vr341fvGLX8Shhx4aEZ9da5x++unx3HPPRefOneOYY46JpUuXxv3331/r93rrrbdi5cqVsfPOO1f6B8nqKC0tjXHjxsU555yT82s3ZsWKFTF37txYvXp17LnnnrW+A3H//v3je9/7Xpx00kkRETFnzpzYZ5994qKLLooePXrET3/60xg8eHBceeWVtXqf2t4ptj7ubFofmXvuuWcMHz48TjvttCr3X3nllXHbbbfF008/Xe1MnWPTdI78ZeocOkdE47pGjtA5NqYhnM/q0Dvyq657h86hc1TQOT6jc+gc1aVz6BwNmWtknWNDGsL5rA6dI7/8W8f69I666R06x2d0Dp2junQOnaMhc42sc2xIQzif1aFz5JfOsT6dw7915JrZWHuHzlG3dA6doyFzjaxzbEhDOJ/VoXPkl86xPp1D58g1s7F2jgi9o6411t6hczR8rpF1jg1pCOezOnSO/NI51qdz6By5ZuocOkddaaydI0LvKASFcJ1cKNfIhXAuIwrnfFaHzpFfOsf6dA6dI9fM+ugcANDQWKC/ESgrK4vnn39+g3cdqo5MJhPDhw+P6dOnR7du3WLnnXeOiIhXXnklXn/99fje974Xt956a7XumFRh8ODBUVxcHOecc0787ne/i/vuuy8GDRoU119/fUREnHLKKTFv3rycSkt9KS8vj6lTp8aNN94YK1asiO9///sxZcqUeP7552OXXXbJOW9z3i21oUmn01FeXl6nv+Rs3759zJgxI/bee++IiFi8eHF06tQp/h979x0eRdm2f/zc3UAKJCRA6JCEGgQVFBRBqUoTEUQEpINSLDQREFSkCyhdpUhCe6UpVRB8qNKsCChFegQh9BI6Sa7fH/llySa7m5ndGbbM+T2OHO+z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/VRu3rxpc+yTTz6RzZs3q5oXGxsr3333nYikrYHFYpHff//devyXX36RggULqpp5//59GTx4sOTMmVP69u0rt2/fVvX19sr895ujv+PUdOvWLWnfvr2Eh4dLbGys/PTTTzbHa9euLZ9++qmqmXrcKfbtt9+WunXr2j2WmpoqdevWlXfeecfjM9u3b29zzbpnzx65d++eqhmZozmUR3M4j+agOdKjOVyP5vD+9aQ7jOcOmoPmoDloDpqD5lAbzUFzGO0ametJc2SO5uB7HWoyqjtoDpqD5qA53InmoDmMdo3M9aQ5Mkdz0BxqMqo5ROgOI7qD5qA5tIrmoDmMdo3M9aQ5Mkdz0BxqojloDhHjmEOE7qA7tInmoDmMdo3M9aQ5Mkdz0BxqojloDhGag+agOVyJ7jCmO4x6jUxz0ByZozloDjXRHDSHiDbmYIwxxrwtk4gGtypkXlXGO145ymQy4fjx44pnvvjiiyhRogS++uoru8d79OiBf//9F2vXrlU8s1OnToruRBcfH694ptrCwsKwZ88e1Xdx+ueffzB79mzMnz8fV69exQsvvIBVq1Yp/nqz2YyoqChUrlzZ6d1Cly9frnimxWLB4cOHERkZCRFB8eLFsX37dkRHR9s8z5W7gd25cwfffvst4uPj8fPPP+Oll15C165d8cILL6ieZbFYcPbsWRQoUED11z7MEhISFD0vKipK8Uyz2QyTyWT3Z57+eZPKu6XmzZsXW7ZswWOPPWb3+F9//YWaNWuququa2WxGo0aNEBgYaP3c6tWrUbduXeTKlcv6uWXLlimeqcd6LlmyBB9++CGuXr2KIUOGoGfPnsiZM6fir7eX2WxGcHAw2rRp4/S/lQkTJqiefejQIWzevBlbtmzB1q1bcefOHTz77LOoVasWateujapVqyqeZfT11HItLRYLEhMTrXegDA0Nxb59+xT9XfowZ9avXx9169bFoEGD7B4fPXo0tm7divXr1yue+cEHH2DFihXWuzzu3LkTx48ft97ZdebMmZg3bx62b9+ueKbZbEbFihVt7mi5b98+xMbG2vx52r17t+KZevTCCy8gPj7erTsrP4w+/fRTTJ48GW+99RY2bdqECxcu4O+//7YenzRpEr7//nts2LBB8czHHnsMN27cQFxcHGrXrq3Jeerx95seLV++HK1bt8azzz6L/fv3o2rVqli9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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\n", + "consumption_oilproduct_2020 = pd.DataFrame(data_results['vQSTInTE'][data_results['vQSTInTE'].sTE.str.startswith('sTEOP') & data_results['vQSTInTE'].sYear.str.startswith('y2020') ].groupby(['sTE','sST']).vQSTInTE.sum()).reset_index().pivot(index='sTE', columns='sST', values='vQSTInTE').fillna(0)\n", + "consumption_oilproduct_2025 = pd.DataFrame(data_results['vQSTInTE'][data_results['vQSTInTE'].sTE.str.startswith('sTEOP') & data_results['vQSTInTE'].sYear.str.startswith('y2025') ].groupby(['sTE','sST']).vQSTInTE.sum()).reset_index().pivot(index='sTE', columns='sST', values='vQSTInTE').fillna(0)\n", + "consumption_oilproduct_2030 = pd.DataFrame(data_results['vQSTInTE'][data_results['vQSTInTE'].sTE.str.startswith('sTEOP') & data_results['vQSTInTE'].sYear.str.startswith('y2030') ].groupby(['sTE','sST']).vQSTInTE.sum()).reset_index().pivot(index='sTE', columns='sST', values='vQSTInTE').fillna(0)\n", + "consumption_oilproduct_2035 = pd.DataFrame(data_results['vQSTInTE'][data_results['vQSTInTE'].sTE.str.startswith('sTEOP') & data_results['vQSTInTE'].sYear.str.startswith('y2035') ].groupby(['sTE','sST']).vQSTInTE.sum()).reset_index().pivot(index='sTE', columns='sST', values='vQSTInTE').fillna(0)\n", + "consumption_oilproduct_2040 = pd.DataFrame(data_results['vQSTInTE'][data_results['vQSTInTE'].sTE.str.startswith('sTEOP') & data_results['vQSTInTE'].sYear.str.startswith('y2040') ].groupby(['sTE','sST']).vQSTInTE.sum()).reset_index().pivot(index='sTE', columns='sST', values='vQSTInTE').fillna(0)\n", + "consumption_oilproduct_2045 = pd.DataFrame(data_results['vQSTInTE'][data_results['vQSTInTE'].sTE.str.startswith('sTEOP') & data_results['vQSTInTE'].sYear.str.startswith('y2045') ].groupby(['sTE','sST']).vQSTInTE.sum()).reset_index().pivot(index='sTE', columns='sST', values='vQSTInTE').fillna(0)\n", + "consumption_oilproduct_2050 = pd.DataFrame(data_results['vQSTInTE'][data_results['vQSTInTE'].sTE.str.startswith('sTEOP') & data_results['vQSTInTE'].sYear.str.startswith('y2050') ].groupby(['sTE','sST']).vQSTInTE.sum()).reset_index().pivot(index='sTE', columns='sST', values='vQSTInTE').fillna(0)\n", + "\n", + "consumption_oilproduct = pd.concat([consumption_oilproduct_2020,consumption_oilproduct_2025,consumption_oilproduct_2030,consumption_oilproduct_2035,consumption_oilproduct_2040,consumption_oilproduct_2045,consumption_oilproduct_2050], axis=1)\n", + "\n", + "# Increase the size of the plot in sucha way that all the years are visible an sST and sES are readable\n", + "plt.figure(figsize=(90, 4))\n", + "# Create a heatmap\n", + "sns.heatmap(consumption_oilproduct, cmap='coolwarm',vmin=0, vmax=consumption_oilproduct.max().max())\n", + "\n", + "#Insert a separator between the years\n", + "plt.axvline(x=[38], color='white')\n", + "plt.axvline(x=[76], color='white')\n", + "plt.axvline(x=[114], color='white')\n", + "plt.axvline(x=[152], color='white')\n", + "plt.axvline(x=[190], color='white')\n", + "plt.axvline(x=[228], color='white')\n", + "\n", + "# Add a label to each axvline\n", + "plt.text(16, -0.5, '2020', fontsize=12, color='black')\n", + "plt.text(54, -0.5, '2025', fontsize=12, color='black')\n", + "plt.text(92, -0.5, '2030', fontsize=12, color='black')\n", + "plt.text(130, -0.5, '2035', fontsize=12, color='black')\n", + "plt.text(168, -0.5, '2040', fontsize=12, color='black')\n", + "plt.text(206, -0.5, '2045', fontsize=12, color='black')\n", + "plt.text(244, -0.5, '2050', fontsize=12, color='black')\n", + "\n", + "# Rotate the x axis labels\n", + "plt.title('Consumption of oil product by ST')\n", + "#move the title more to the top\n", + "plt.xlabel('sST')\n", + "plt.ylabel('sTE')" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sSTsESsYearvEmiCO2ST
0sST_DSTRA_LNP_CAGSNsES_DSTRA_PAS_URBNy20203236.260854
7sST_DSTRA_LNP_CAGSNsES_DSTRA_PAS_G50y2020994.451350
14sST_DSTRA_LNP_CAGSNsES_DSTRA_PAS_G500y20201388.796718
21sST_DSTRA_LNP_CADSTsES_DSTRA_PAS_URBNy20207269.488197
28sST_DSTRA_LNP_CADSTsES_DSTRA_PAS_G50y20203181.967310
...............
413sST_DSTRA_LNF_TRUBICNGsES_DSTRA_FRE_G500y20208240.917166
420sST_DSTRA_LNF_TRUBIELEsES_DSTRA_FRE_G50y20200.000000
427sST_DSTRA_LNF_TRUBIELEsES_DSTRA_FRE_G500y20200.000000
434sST_DSTRA_SEAF_SHIPDIEsES_DSTRA_FRE_EXPy20200.000000
441sST_DSTRA_SEAF_SHIPDIEsES_DSTRA_FRE_INTy20200.000000
\n", + "

64 rows × 4 columns

\n", + "
" + ], + "text/plain": [ + " sST sES sYear vEmiCO2ST\n", + "0 sST_DSTRA_LNP_CAGSN sES_DSTRA_PAS_URBN y2020 3236.260854\n", + "7 sST_DSTRA_LNP_CAGSN sES_DSTRA_PAS_G50 y2020 994.451350\n", + "14 sST_DSTRA_LNP_CAGSN sES_DSTRA_PAS_G500 y2020 1388.796718\n", + "21 sST_DSTRA_LNP_CADST sES_DSTRA_PAS_URBN y2020 7269.488197\n", + "28 sST_DSTRA_LNP_CADST sES_DSTRA_PAS_G50 y2020 3181.967310\n", + ".. ... ... ... ...\n", + "413 sST_DSTRA_LNF_TRUBICNG sES_DSTRA_FRE_G500 y2020 8240.917166\n", + "420 sST_DSTRA_LNF_TRUBIELE sES_DSTRA_FRE_G50 y2020 0.000000\n", + "427 sST_DSTRA_LNF_TRUBIELE sES_DSTRA_FRE_G500 y2020 0.000000\n", + "434 sST_DSTRA_SEAF_SHIPDIE sES_DSTRA_FRE_EXP y2020 0.000000\n", + "441 sST_DSTRA_SEAF_SHIPDIE sES_DSTRA_FRE_INT y2020 0.000000\n", + "\n", + "[64 rows x 4 columns]" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSTRA')) & (data_results['vEmiCO2ST'].sYear=='y2020')]" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sSTsESsYearvEmiCO2STPro
980sST_DSIND_IISsES_DSIND_IISy20200.0
987sST_DSIND_CHEsES_DSIND_CHEy20200.0
994sST_DSIND_NFMsES_DSIND_NFMy20200.0
1001sST_DSIND_NMMsES_DSIND_NMMy20200.0
1008sST_DSIND_TRAsES_DSIND_TRAy20200.0
1015sST_DSIND_MACsES_DSIND_MACy20200.0
1022sST_DSIND_MINsES_DSIND_MINy20200.0
1029sST_DSIND_FBTsES_DSIND_FBTy20200.0
1036sST_DSIND_PPPsES_DSIND_PPPy20200.0
1043sST_DSIND_WOOsES_DSIND_WOOy20200.0
1050sST_DSIND_CONsES_DSIND_CONy20200.0
1057sST_DSIND_TEXsES_DSIND_TEXy20200.0
1064sST_DSIND_OTHsES_DSIND_OTHy20200.0
\n", + "
" + ], + "text/plain": [ + " sST sES sYear vEmiCO2STPro\n", + "980 sST_DSIND_IIS sES_DSIND_IIS y2020 0.0\n", + "987 sST_DSIND_CHE sES_DSIND_CHE y2020 0.0\n", + "994 sST_DSIND_NFM sES_DSIND_NFM y2020 0.0\n", + "1001 sST_DSIND_NMM sES_DSIND_NMM y2020 0.0\n", + "1008 sST_DSIND_TRA sES_DSIND_TRA y2020 0.0\n", + "1015 sST_DSIND_MAC sES_DSIND_MAC y2020 0.0\n", + "1022 sST_DSIND_MIN sES_DSIND_MIN y2020 0.0\n", + "1029 sST_DSIND_FBT sES_DSIND_FBT y2020 0.0\n", + "1036 sST_DSIND_PPP sES_DSIND_PPP y2020 0.0\n", + "1043 sST_DSIND_WOO sES_DSIND_WOO y2020 0.0\n", + "1050 sST_DSIND_CON sES_DSIND_CON y2020 0.0\n", + "1057 sST_DSIND_TEX sES_DSIND_TEX y2020 0.0\n", + "1064 sST_DSIND_OTH sES_DSIND_OTH y2020 0.0" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data_results['vEmiCO2STPro'][(data_results['vEmiCO2STPro'].sST.str.startswith('sST_DSIND')) & (data_results['vEmiCO2STPro'].sYear=='y2020')]" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sSTsESsYearvEmiCO2ST
0sST_DSTRA_LNP_CAGSNsES_DSTRA_PAS_URBNy20203236.260854
7sST_DSTRA_LNP_CAGSNsES_DSTRA_PAS_G50y2020994.451350
14sST_DSTRA_LNP_CAGSNsES_DSTRA_PAS_G500y20201388.796718
21sST_DSTRA_LNP_CADSTsES_DSTRA_PAS_URBNy20207269.488197
28sST_DSTRA_LNP_CADSTsES_DSTRA_PAS_G50y20203181.967310
...............
413sST_DSTRA_LNF_TRUBICNGsES_DSTRA_FRE_G500y20208240.917166
420sST_DSTRA_LNF_TRUBIELEsES_DSTRA_FRE_G50y20200.000000
427sST_DSTRA_LNF_TRUBIELEsES_DSTRA_FRE_G500y20200.000000
434sST_DSTRA_SEAF_SHIPDIEsES_DSTRA_FRE_EXPy20200.000000
441sST_DSTRA_SEAF_SHIPDIEsES_DSTRA_FRE_INTy20200.000000
\n", + "

64 rows × 4 columns

\n", + "
" + ], + "text/plain": [ + " sST sES sYear vEmiCO2ST\n", + "0 sST_DSTRA_LNP_CAGSN sES_DSTRA_PAS_URBN y2020 3236.260854\n", + "7 sST_DSTRA_LNP_CAGSN sES_DSTRA_PAS_G50 y2020 994.451350\n", + "14 sST_DSTRA_LNP_CAGSN sES_DSTRA_PAS_G500 y2020 1388.796718\n", + "21 sST_DSTRA_LNP_CADST sES_DSTRA_PAS_URBN y2020 7269.488197\n", + "28 sST_DSTRA_LNP_CADST sES_DSTRA_PAS_G50 y2020 3181.967310\n", + ".. ... ... ... ...\n", + "413 sST_DSTRA_LNF_TRUBICNG sES_DSTRA_FRE_G500 y2020 8240.917166\n", + "420 sST_DSTRA_LNF_TRUBIELE sES_DSTRA_FRE_G50 y2020 0.000000\n", + "427 sST_DSTRA_LNF_TRUBIELE sES_DSTRA_FRE_G500 y2020 0.000000\n", + "434 sST_DSTRA_SEAF_SHIPDIE sES_DSTRA_FRE_EXP y2020 0.000000\n", + "441 sST_DSTRA_SEAF_SHIPDIE sES_DSTRA_FRE_INT y2020 0.000000\n", + "\n", + "[64 rows x 4 columns]" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data_results['vEmiCO2ST'][(data_results['vEmiCO2ST'].sST.str.startswith('sST_DSTRA')) & (data_results['vEmiCO2ST'].sYear=='y2020')]" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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9TqdTkmXL1++4/Hq9Xr9kiVL9Nu3b9efOnVK//333+sHDhyob9Wqlb6kpKRGn++djLmuPeNy77zzjj4sLEwP6D/77DMlvy79DBsTr15ft55vQECAfuzYsapY8vPzles1+TMshKg5MogXopZ89NFH+kaNGumLiopU+Y899pj+ySefNFinQ4cO+ri4OOVz586d9RMmTFA+l5aW6ps3b66Pj4+vtN/Vq1frzc3N9VevXtXr9Xr9V199pTcxMdHn5uYqZd5//329nZ2dvri4uM7Fq9frDQ6K/q224v3xxx/1gP7EiRN6vd7451uXYtbr694z3r9/v75FixZ6nU5XIba6+DN8o3j1+rr1fAMCAvQxMTGVxlGdn2EhxJ0jy2mEqCVDhw6ltLSUjRs3Knl//fUXX375JdHR0RXKl5WVceHCBRo1agTAlStX+P777wkJCVHKmJiYEBISwu7duyvtNz8/Hzs7O8zMrp31tnv3bnx8fFQHk4SGhlJQUMChQ4fqXLzlJkyYQJMmTejcuTPLli1D/68jL2oj3osXL5Kamkrbtm1p1aoVYPzzrUsxl6srz/jSpUs88cQTvPfeezg7O1dot679DFcVb7m68nwB0tPTadKkCffffz+xsbFcunRJuVadn2EhxJ0jg3ghaomVlRVPPPEEqampSt7HH39M69atCQwMrFD+7bffprCwkGHDhgHw999/U1paWuFUwGbNmpGbm2uwz7///ps333yTZ555RsnLzc012Eb5tboWL8DMmTNZvXo1GRkZDB48mPHjx5OcnKwqcyfjXbRoETY2NtjY2LBp0yYyMjIwNzcHjH++dSlmqFvP+MUXX6R79+489thjFdqEuvczXFW8ULee7xNPPMHHH39MZmYmsbGx/N///R9PPvmkcr06P8NCiDvHrOoiQojbZezYsTz88MP897//pUWLFqSlpTFq1Cg0Go2q3IoVK4iLi2PDhg04OTndVF8FBQX079+fDh06MGPGjHod7xtvvKH82c/Pj4sXLzJ//nxeeOGFWok3MjKS3r17o9PpePvttxk2bBjffvstlpaW1W6rrsRcV57xxo0b+eabb9i/f3+179GQuhJvXXm+gOqXZB8fH1xcXAgODuaXX36hXbt21WpLCHEH1fJyHiHueQ8++KB+zpw5+u+++05vYmKi/+2331TXV65cqbeystJ/8cUXqvzi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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\n", + "# Make a single heatmap that includes all the years\n", + "# Create a df that contains the emissions of each ST for each year\n", + "# The rows are the sST and the columns are sES\n", + "# Each intersection should be divided in 7 columns, one for each year\n", + "# The value of each intersection should be the emissions of the ST for that year\n", + "# The heatmap should have a color scale that goes from 0 to the maximum value of the emissions\n", + "\n", + "# Create a df that contains the emissions of each ST for each year in the transport sector\n", + "emissions_2020 = vEmiCO2CE_HEATMAP_2020.pivot(index='sCE', columns='sYear', values='vEmiCO2CE')\n", + "emissions_2025 = vEmiCO2CE_HEATMAP_2025.pivot(index='sCE', columns='sYear', values='vEmiCO2CE')\n", + "emissions_2030 = vEmiCO2CE_HEATMAP_2030.pivot(index='sCE', columns='sYear', values='vEmiCO2CE')\n", + "emissions_2035 = vEmiCO2CE_HEATMAP_2035.pivot(index='sCE', columns='sYear', values='vEmiCO2CE')\n", + "emissions_2040 = vEmiCO2CE_HEATMAP_2040.pivot(index='sCE', columns='sYear', values='vEmiCO2CE')\n", + "emissions_2045 = vEmiCO2CE_HEATMAP_2045.pivot(index='sCE', columns='sYear', values='vEmiCO2CE')\n", + "emissions_2050 = vEmiCO2CE_HEATMAP_2050.pivot(index='sCE', columns='sYear', values='vEmiCO2CE')\n", + "\n", + "# Create a df that contains the emissions of each ST for each year\n", + "emissions = pd.concat([emissions_2020, emissions_2025, emissions_2030, emissions_2035, emissions_2040, emissions_2045, emissions_2050], axis=1)\n", + "\n", + "# replace NaN values with 0\n", + "# emissions.fillna(0, inplace=True)\n", + "\n", + "# Increase the size of the plot in sucha way that all the years are visible an sST and sES are readable\n", + "plt.figure(figsize=(5, 8))\n", + "# Create a heatmap\n", + "sns.heatmap(emissions, cmap='coolwarm',vmin=0, vmax=emissions.max().max())\n", + "#Insert a separator between the years\n", + "plt.axvline(x=[1], color='white')\n", + "plt.axvline(x=[2], color='white')\n", + "plt.axvline(x=[3], color='white')\n", + "plt.axvline(x=[4], color='white')\n", + "plt.axvline(x=[5], color='white')\n", + "plt.axvline(x=[6], color='white')\n", + "\n", + "\n", + "# Rotate the x axis labels\n", + "plt.title('CO2 emissions of each CE (vQCEPriIN + vQCESecIN + vQCEStoIN) for each year [ktCO2]')\n", + "#move the title more to the top\n", + "plt.xlabel('sYear')\n", + "plt.ylabel('sCE')\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sCEsYearvEmiCO2CE
0sCENUCLEARy20200.0
1sCENUCLEARy20250.0
2sCENUCLEARy20300.0
3sCENUCLEARy20350.0
4sCENUCLEARy20400.0
............
191sCECOGENOTHBIOy20300.0
192sCECOGENOTHBIOy20350.0
193sCECOGENOTHBIOy20400.0
194sCECOGENOTHBIOy20450.0
195sCECOGENOTHBIOy20500.0
\n", + "

182 rows × 3 columns

\n", + "
" + ], + "text/plain": [ + " sCE sYear vEmiCO2CE\n", + "0 sCENUCLEAR y2020 0.0\n", + "1 sCENUCLEAR y2025 0.0\n", + "2 sCENUCLEAR y2030 0.0\n", + "3 sCENUCLEAR y2035 0.0\n", + "4 sCENUCLEAR y2040 0.0\n", + ".. ... ... ...\n", + "191 sCECOGENOTHBIO y2030 0.0\n", + "192 sCECOGENOTHBIO y2035 0.0\n", + "193 sCECOGENOTHBIO y2040 0.0\n", + "194 sCECOGENOTHBIO y2045 0.0\n", + "195 sCECOGENOTHBIO y2050 0.0\n", + "\n", + "[182 rows x 3 columns]" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data_results['vEmiCO2CE'][data_results['vEmiCO2CE'].sCE.isin(data_input['sCE_Ele'].sCE_Ele)]\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 1.05, 'CO2 emissions of each TE (Transport + Losses) for each year [ktCO2]')" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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ARKJBN98841W/zhU5v104cIFvPPOOwgKCkJmZibWrVuH999/Hz4+PgAAHx8fDBkyBCtXrlQMTx48eBBr1qxBnz59NJ531qZNG+zduxdffPEFnJyc4Orqqni45EX4/fff8cknnyild+vWDW+//TbefPNNzJw5ExcvXoSPjw/27NmDHTt2YNKkSYpH8avrO+XTTz/Fvn370KFDBwwfPhzNmjXD7du3ceTIEezdu1fRcNP0Ph4+fBi3b99WPM5fWbr4Tivz5Zdf4vXXX4e3tzeGDx8ONzc3XL9+HZmZmbhy5YpinanevXtj3rx5iIiIQOfOnXH8+HGsX79e6bM4ePBgrF27FlOmTMHBgwfxxhtv4P79+9i7dy/GjBlT5ddAlcGDB2PJkiXYt2+fymVbNL2PvXv3xtatW9G3b1/06tULFy5cwPLly9GsWTP8888/1RavOgYGBli3bh369OmDfv364aefflLMBWvTpg02b96MKVOmoF27drC0tMTbb78NY2NjbN26Ff7+/ujSpQv69esHX19fGBsb4+TJk9iwYQNsbW0V850GDhyIQ4cOYfHixTh16hQGDhwIW1tbHDlyBImJibC3t0dycrKoVzEoKAjnz5/HRx99hP/+97/473//qzjm6OiIHj16aH/xGj8P+IzTp08Lw4cPF1xcXAQTExPByspK8PX1FeLj40WPqwrC08esY2NjhTZt2ggWFhaCubm50Lp1ayEuLk54/PixKO++ffvUPmIOQJgzZ45G8a1cuVJo06aNYGZmJlhZWQne3t7CRx99JFrdXd1j/VDxyLOqxyefXzYhLS1NePfddwUnJyfBxMREcHJyEsLCwkSPY65YsULo0qWLYG9vL0ilUsHd3V2YNm2acPfuXUWe55dNKLN06VKhadOmgrGxseDo6CiMHj1auHPnjihP165dVT72PGTIENGjqprEoc7169eFiIgIoU6dOoKJiYng7e2t8jFaTZdNKPPdd98Jr7/+umBhYSFYWFgITZs2FcaOHSvk5OQo8pw6dUrw9/cXLC0thTp16gjDhw8X/vjjD5WP8p44cULo27evYGNjI5iamgqenp7Cv//9b8VxdSv7qnv9y1PVZRNUxa3Ka6+9JgwbNkztcXXLJqh7BP7XX38VOnbsKJiZmQlOTk7CRx99pFgy5NmlQarz/VT2ep86dUoIDQ0VrKysBFtbW2HcuHHCw4cPReU/efJEiIqKElxdXQVjY2OhYcOGQmRkpNJ3S3nvsb/++kvo0qWLYGZmJgCo9BIK2i6boG6bP3++IAiCcO/ePWHy5MmCk5OTYGxsLDRu3FhYtGiRaGmP6vpOEYSnn9uxY8cKDRs2FIyNjQW5XC74+fkJK1eurHRZ06dPFxo1aiSKVZ3yVtDW5jutPOfOnRMGDx4syOVywdjYWKhfv77Qu3dvITk5WZHn0aNHwtSpU4V69eoJZmZmgq+vr5CZmSl07dpV6bP84MEDYebMmYr3o1wuF0JDQ4Vz584JglD+4/WV+XdLEJ5+lxgYGAhXrlxReVyT+1haWiosXLhQcHZ2FqRSqdCqVSvhhx9+UPrcVnZZgMqulP7gwQOha9eugqWlpfDbb78JgiAI//zzj/D+++8LNjY2AgClz9idO3eE2bNnC97e3oK5ublgamoqtGjRQoiMjBRyc3OV6t2+fbvQo0cPwdbWVpBKpYKHh4cwdepUle+38j6Xqr6/q7JsguR/FRHRS+qbb77B2LFjcfnyZcWj9LVN2UKO+fn51beIHr1wRUVFcHFxwYwZMxS/ikHVp1WrVrCzs0NaWlpNh6Lk4sWLcHV1RXx8PAYMGACZTKbR05e1jfC/qSZ///03WrdujUWLFuHDDz/U6NxKzaEiohdv4MCBaNSoUaUe0CDShaSkJBgbGyut30ba+/3333Hs2LFyf13kZTB+/HjUrVtXaX7Uq+Lu3buoW7cuWrduXelzq+95QSLSCQMDg1fmqUWq3UaNGsXGVDU7ceIEDh8+jJiYGNSrVw/9+/ev6ZBUksvloqeqy5vPXJtZWlqKrrO8p8+fxwYVERFRDUlOTsa8efPg6emJjRs3ql22pqbpahmRl42RkVGVr5NzqIiIiIi0xDlURERERFpig4qIiIhIS2xQEREREWmJDSoiIiIiLbFBRURERKQlNqiIiIiItMQGFREREZGW2KAiIiIi0hIbVERERERaYoOKiIiISEtsUBERERFpiQ0qIiIiIi2xQUVERESkJTaoiIiIiLTEBhURERGRltigIiIiItISG1REREREWmKDioiIiEhLbFARERERaYkNKiIiIiItsUFFREREpCU2qIiIiIi0xAYVERERkZbYoCIiIiLSEhtURERERFpig4qIiIhIS2xQEREREWmJDSoiIiIiLbFBRURERKQlNqiIiIiItMQGFREREeHLL7+Ei4sLTE1N0aFDBxw8eFBt3pMnTyIkJAQuLi6QSCSIi4urUpmPHj3C2LFjYW9vD0tLS4SEhOD69evVeVkvDBtUREREem7z5s2YMmUK5syZgyNHjsDHxweBgYG4ceOGyvwPHjyAm5sbPv30U8jl8iqXOXnyZHz//ffYsmULfvnlF1y7dg3BwcE6uUZdkwiCINR0EERERFRzOnTogHbt2mHp0qUAgNLSUjRs2BDjx4/HjBkzyj3XxcUFkyZNwqRJkypV5t27d1G3bl1s2LABoaGhAIC//voLXl5eyMzMRMeOHav/QnWIPVRERESvoKKiIhQWFoq2oqIipXyPHz/G4cOH4e/vr0gzMDCAv78/MjMzq1S3JmUePnwYT548EeVp2rQpGjVqVOV6a5JRTQdAtdf5c+dqOgSNSSQSuLq5AQAunD+Pl71jlvHqXm2LmfG+GG7u7tVa3o/GntVaXmUcmhmGqKgoUdqcOXMwd+5cUdrNmzdRUlICR0dHUbqjoyP++uuvKtWtSZl5eXkwMTGBjY2NUp68vLwq1VuT2KAiIiJ6BUVGRmLKlCmiNKlUWkPRvPrYoCIiItIRibGkxuqWSqUaNaDq1KkDQ0NDpafrrl+/rnbCeXWUKZfL8fjxYxQUFIh6qbSptyZxDhUREZEeMzExQZs2bZCWlqZIKy0tRVpaGjp16qSzMtu0aQNjY2NRnpycHFy+fLnK9dYk9lARERHpuSlTpmDIkCFo27Yt2rdvj7i4ONy/fx8REREAgMGDB6N+/fqIjo4G8HTS+alTpxT/f/XqVRw7dgyWlpbw8PDQqExra2sMGzYMU6ZMgZ2dHWQyGcaPH49OnTrVuif8ADaoiIiIdMbAqOaG/Cqjf//+yM/Px+zZs5GXl4eWLVsiJSVFMan88uXLMDD4/0Gta9euoVWrVor9zz//HJ9//jm6du2K9PR0jcoEgNjYWBgYGCAkJARFRUUIDAzEsmXLXsxFVzOuQ0VVxqf8dIfx6l5ti5nxvhjV/ZRfisyrWsurjKDC7BqrWx+xh4qIiEhHJMacqqwveKeJiIiItMQeKiIiIh2pLXOoSHvsoXpO2S9nq9vCw8MBQO3xTZs2AQDS09NF6WZmZmjevDlWrlwpqi88PBx9+vQRpf39998YOnQonJycYGJiAmdnZ0ycOBG3bt0S5evWrZuifKlUivr16+Ptt9/G1q1bla5LIpFg+/btov3y4iciIiLNsYfqOYcOHUJJSQkAICMjAyEhIcjJyYFMJgMAmJmZKfImJSUhKChIdP7zS+iXnfvw4UN8//33GD16NNzd3eHn56ey/vPnz6NTp05o0qQJNm7cCFdXV5w8eRLTpk3Drl278Ntvv8HOzk6Rf/jw4Zg3bx6Ki4tx5coVbNu2DQMGDEB4eLhS4+15msRPREREFdPrBlVycjKioqJw9uxZmJubo1WrVtixYwcsLCwAQNFwcXBwUNnQsLGxqXA112fPnTBhApYsWYIjR46obVCNHTsWJiYm2LNnj6Lx1qhRI7Rq1Qru7u6YOXMmvvrqK0V+c3NzRQwNGjRAx44d0bRpUwwdOhT9+vUT/ehkVeInIqKqq8mV0unF0tshv9zcXISFhWHo0KHIzs5Geno6goODdfZoryAISElJweXLl9GhQweVeW7fvo3du3djzJgxop4w4OkS/QMHDsTmzZsrjHHIkCGwtbVVOfRHRERE1U9ve6hyc3NRXFyM4OBgODs7AwC8vb0rVUZYWBgMDQ1FaadOnUKjRo0U+w0aNAAAFBUVobS0FPPmzUOXLl1UlnfmzBkIggAvL9Xrlnh5eeHOnTvIz8+Hg4OD2rgMDAzQpEkTXLx4Uev4yxQVFaGoqEgpjT+0SUSkHiel6w+9bVD5+PjAz88P3t7eCAwMREBAAEJDQ2Fra6txGbGxsUpDak5OTqL9AwcOwMrKCkVFRTh48CDGjRsHOzs7jB49Wm251dFLJggCJJLyP8iaxF8mOjoaUVFRorQJ48dj4sSJ2gVKRET0CtDbBpWhoSFSU1ORkZGBPXv2ID4+HjNnzkRWVhZcXV01KkMulyt+s0gdV1dXxRyq5s2bIysrCwsWLFDZoPLw8IBEIkF2djb69u2rdDw7Oxu2traoW7duuXWWlJTgzJkzaNeundbxl4mMjMSUKVNEaVevXNHoXCIioled3s6hAp4uHeDr64uoqCgcPXoUJiYm2LZtm07rNDQ0xMOHD1Ues7e3R48ePbBs2TKlPHl5eVi/fj369+9fYc/TmjVrcOfOHYSEhFRb3FKpFDKZTLRxuI+IqHwSY0mNbfRi6W0PVVZWFtLS0hAQEAAHBwdkZWUhPz9f7fwlVQoKCpCXlydKs7KyUjwlCAA3btzAo0ePFEN+33zzDUJDQ9WWuXTpUnTu3BmBgYH45JNPRMsm1K9fHwsWLBDlf/DgAfLy8kTLJsTGxmL06NF48803tY6fiIiIKqa3DSqZTIb9+/cjLi4OhYWFcHZ2RkxMDHr27KlxGREREUpp0dHRmDFjhmLf09MTAGBkZISGDRti5MiRmDt3rtoyGzdujN9//x1z5sxBv379cPv2bcjlcvTp0wdz5swRrUEFAKtWrcKqVatgYmICe3t7tGnTBps3b1Y5ZFiV+ImIqOo4KV1/6G2DysvLCykpKeXm6datm9oJ4hVNHC/v3GetXr1aKc3Z2Vll+vPS09MrzFPm+Vhqyy+/ExER1QZ626AiIiLSNYkhe6j0hV5PSiciIiKqDmxQEREREWmJQ35EREQ6YsAhP73BHioiIiIiLbGHioiISEckBuyh0hfsoSIiIiLSEhtURERERFrikB8REZGOSAzZb6EveKeJiIiItMQeKiIiIh3hsgn6gz1URERERFpiDxUREZGOcNkE/cEeKiIiIiItsUFFREREpCUO+REREekIJ6XrD/ZQEREREWmJPVREREQ6ImEPld5gDxURERGRlvS+QeXi4gKJRKJ2Cw8PBwC1xzdt2gQASE9PF6WbmZmhefPmWLlypai+8PBw9OnTR5T2999/Y+jQoXBycoKJiQmcnZ0xceJE3Lp1S5SvW7duKmMYNWoUVq9eXe51SCQSXLx4EXPnzkXLli2VXoeLFy9CIpHg2LFj1fXSEhER6Q29H/I7dOgQSkpKAAAZGRkICQlBTk4OZDIZAMDMzEyRNykpCUFBQaLzbWxsRPtl5z58+BDff/89Ro8eDXd3d/j5+ams//z58+jUqROaNGmCjRs3wtXVFSdPnsS0adOwa9cu/Pbbb7Czs1PkHz58OObNmycqw9zcHMbGxqLYgoOD0aJFC1HeunXrVuKVISIibUkM9L7fQm/oVYMqOTkZUVFROHv2LMzNzdGqVSvs2LEDFhYWAKBouDg4OCg1lICnjSe5XF5uHc+eO2HCBCxZsgRHjhxR26AaO3YsTExMsGfPHkXjrVGjRmjVqhXc3d0xc+ZMfPXVV4r85ubmamN4tvFnYmJSbl4iIiKqPnrTdM7NzUVYWBiGDh2K7OxspKenIzg4GIIg6KQ+QRCQkpKCy5cvo0OHDirz3L59G7t378aYMWNEjSEAkMvlGDhwIDZv3qyzGImISLckBpIa2+jF0pseqtzcXBQXFyM4OBjOzs4AAG9v70qVERYWBkNDQ1HaqVOn0KhRI8V+gwYNAABFRUUoLS3FvHnz0KVLF5XlnTlzBoIgwMvLS+VxLy8v3LlzB/n5+XBwcAAALFu2DF9//bUo34oVKzBw4ECNr+P48eOwtLQUpbHRRkREVHV606Dy8fGBn58fvL29ERgYiICAAISGhsLW1lbjMmJjY+Hv7y9Kc3JyEu0fOHAAVlZWKCoqwsGDBzFu3DjY2dlh9OjRasutTGNm4MCBmDlzpijN0dFR4/MBwNPTEzt37hSlXb16Fd26dVN7TlFREYqKipTSpFJppeomItInXNhTf+hNg8rQ0BCpqanIyMjAnj17EB8fj5kzZyIrKwuurq4alSGXy+Hh4VFuHldXV8UcqubNmyMrKwsLFixQ2aDy8PCARCJBdnY2+vbtq3Q8Ozsbtra2osnk1tbWFcZQERMTE6UyjIzKfytER0cjKipKlDZh/HhMnDhRq1iIiIheBXozhwp4uvSBr68voqKicPToUZiYmGDbtm06rdPQ0BAPHz5Uecze3h49evTAsmXLlPLk5eVh/fr16N+/PySSmv8LJzIyEnfv3hVto0aNqumwiIiIXgp600OVlZWFtLQ0BAQEwMHBAVlZWcjPz1c7f0mVgoIC5OXlidKsrKwUTwkCwI0bN/Do0SPFkN8333yD0NBQtWUuXboUnTt3RmBgID755BPRsgn169fHggULRPkfPHigFINUKq3U0GVVSKVSpeG9mxzuIyIqFyeH6w+9aVDJZDLs378fcXFxKCwshLOzM2JiYtCzZ0+Ny4iIiFBKi46OxowZMxT7np6eAJ4OoTVs2BAjR47E3Llz1ZbZuHFj/P7775gzZw769euH27dvQy6Xo0+fPpgzZ45oDSoAWLVqFVatWiVKCwwMREpKisbXQURERNVLIvDxLqqi8+fO1XQIGpNIJHB1cwMAXDh//qV/qpHx6l5ti5nxvhhu7u7VWt6fb3Wr1vIq47Wf0musbn2kV3OoiIiIiHSBDSoiIiIiLenNHCoiIqIXjZPS9Qd7qIiIiIi0xB4qIiIiHeFK6fqDPVREREREWmIPFRERkY5wDpX+YA8VERERkZbYoCIiIiLSEof8iIiIdERiwH4LfcE7TURERKQl9lARERHpCCel6w/2UBERERFpiQ0qIiIiIi1xyI+IiEhHOOSnP9hDRURERKQl9lARERHpCHuo9Ad7qIiIiIi0xAYVERERkZY45EdERKQjXCldf/BOq+Hi4gKJRKJ2Cw8PBwC1xzdt2gQASE9PF6WbmZmhefPmWLlypai+8PBw9OnTR5T2999/Y+jQoXBycoKJiQmcnZ0xceJE3Lp1S5SvW7dukEgk+PTTT5Wuo1evXpBIJJg7d67SsY0bN8LQ0BBjx46t+gtFRERE7KFS59ChQygpKQEAZGRkICQkBDk5OZDJZAAAMzMzRd6kpCQEBQWJzrexsRHtl5378OFDfP/99xg9ejTc3d3h5+ensv7z58+jU6dOaNKkCTZu3AhXV1ecPHkS06ZNw65du/Dbb7/Bzs5Okb9hw4ZYvXo1ZsyYoUi7evUq0tLSUK9ePZV1JCQk4KOPPsKKFSsQExMDU1NTzV8gIiKqkIEhJ6XrC/ZQAUhOToa3tzfMzMxgb28Pf39/mJubQy6XQy6XKxouDg4OijRra2vF+TY2Nor0su35xknZua6urpgwYQJcXV1x5MgRtTGNHTsWJiYm2LNnD7p27YpGjRqhZ8+e2Lt3L65evYqZM2eK8vfu3Rs3b97Er7/+qkhbs2YNAgIC4ODgoFT+hQsXkJGRgRkzZqBJkybYunVrlV47IiJ6NXz55ZdwcXGBqakpOnTogIMHD5abf8uWLWjatClMTU3h7e2Nn376SXRc3QjOokWLFHlUjQapGm2pDfS+QZWbm4uwsDAMHToU2dnZSE9PR3BwMARB0El9giAgJSUFly9fRocOHVTmuX37Nnbv3o0xY8aIesIAQC6XY+DAgdi8ebMoRhMTEwwcOBBJSUmKtNWrV2Po0KEq60hKSkKvXr1gbW2NQYMGISEhoRqujoiIniUxkNTYVhmbN2/GlClTMGfOHBw5cgQ+Pj4IDAzEjRs3VObPyMhAWFgYhg0bhqNHj6JPnz7o06cPTpw4ociTm5sr2hITEyGRSBASEiIqa968eaJ848ePr/wL/RJggyo3F8XFxQgODoaLiwu8vb0xZswYWFpaalxGWFgYLC0tRdvly5dFeRo0aABLS0uYmJigV69emDNnDrp06aKyvDNnzkAQBHh5eak87uXlhTt37iA/P1+UPnToUHz77be4f/8+9u/fj7t376J3795K55eWlmL16tUYNGgQAGDAgAH473//iwsXLmh8zURE9Or44osvMHz4cERERKBZs2ZYvnw5zM3NkZiYqDL/4sWLERQUhGnTpsHLywvz589H69atsXTpUkWe50duduzYgTfffBNubm6isqysrET5LCwsdHqtuqL3DSofHx/4+fnB29sb7733HlatWoU7d+5UqozY2FgcO3ZMtDk5OYnyHDhwQHHs66+/xsKFC/HVV1+VW25le8l8fHzQuHFjJCcnIzExEf/6179gZKQ8TS41NRX379/HW2+9BQCoU6cOevToofaDAwBFRUUoLCwUbUVFRZWKj4iIXhxNv7cfP36Mw4cPw9/fX5FmYGAAf39/ZGZmqiw7MzNTlB8AAgMD1ea/fv06fvzxRwwbNkzp2Keffgp7e3u0atUKixYtQnFxcWUu86Wh9w0qQ0NDpKamYteuXWjWrBni4+Ph6elZqd4auVwODw8P0fZ8Q8bV1RUeHh5o3rw5IiIi8K9//QsLFixQWZ6HhwckEgmys7NVHs/OzoatrS3q1q2rdGzo0KH48ssvkZycrHa4LyEhAbdv34aZmRmMjIxgZGSEn376CWvWrEFpaanKc6Kjo2FtbS3ali9fXt7LQkSk9yQGBjW2qfrejo6OVorx5s2bKCkpgaOjoyjd0dEReXl5Kq8rLy+vUvnXrFkDKysrBAcHi9InTJiATZs2Yd++fRg5ciQWLlyIjz76qDIv8UtD7xtUwNOJc76+voiKisLRo0dhYmKCbdu26bROQ0NDPHz4UOUxe3t79OjRA8uWLVPKk5eXh/Xr16N///6QSJTHyN9//30cP34cLVq0QLNmzZSO37p1Czt27MCmTZtEPWpHjx7FnTt3sGfPHpUxRUZG4u7du6Jt1KhRVbhyIiJ6EVR9b0dGRtZILImJiRg4cKDSA1tTpkxBt27d8Nprr2HUqFGIiYlBfHx8rRwB0ftlE7KyspCWlqZ4Gi4rKwv5+flq5y+pUlBQoNQqt7KyEo0D37hxA48ePUJRUREOHjyIb775BqGhoWrLXLp0KTp37ozAwEB88sknomUT6tevr7Z3y9bWFrm5uTA2NlZ5/JtvvoG9vT369eun1CB76623kJCQoLQEBABIpVJIpVJR2s3n9omISKwmf8tP1fe2KnXq1IGhoSGuX78uSr9+/TrkcrnKc+Ryucb5Dxw4gJycHGzevLnCWDp06IDi4mJcvHgRnp6eFeZ/meh9D5VMJsP+/fvx1ltvoUmTJpg1axZiYmLQs2dPjcuIiIhAvXr1RFt8fLwoj6enJ+rVqwcPDw9Mnz4dI0eOVMrzrMaNG+P333+Hm5sb+vXrB3d3d4wYMQJvvvkmMjMzRWtQPc/GxkbtpL7ExET07dtXZe9WSEgIdu7ciZs3b2p45UREVNuZmJigTZs2SEtLU6SVlpYiLS0NnTp1UnlOp06dRPmBp/NzVeVPSEhAmzZt4OPjU2Esx44dg4GBgcrlfl52et9D5eXlhZSUlHLzdOvWTe0E8Yomjpd37rNWr16tlObs7Kwy/Xnp6enlHj927Jji///880+1+fr164d+/fpVWB8REb1apkyZgiFDhqBt27Zo37494uLicP/+fURERAAABg8ejPr16yvmYE2cOBFdu3ZFTEwMevXqhU2bNuH3339X+hWQwsJCbNmyBTExMUp1ZmZmIisrC2+++SasrKyQmZmJyZMnY9CgQbC1tdX9RVczvW9QERER6UpNDvlVRv/+/ZGfn4/Zs2cjLy8PLVu2REpKimLi+eXLl2HwzO8Sdu7cGRs2bMCsWbPw8ccfo3Hjxti+fTtatGghKnfTpk0QBAFhYWFKdUqlUmzatAlz585FUVERXF1dMXnyZEyZMkW3F6sjEkFXK1jSK+/8uXM1HYLGJBIJXP+39smF8+d1tnBrdWG8ulfbYma8L4abu3u1lndpRJ9qLa8ynFdur7G69RF7qIiIiHREYqD3U5X1Bu80ERERkZbYQ0VERKQjtWUOFWmPPVREREREWmKDioiIiEhLHPIjIiLSEU5K1x+800RERERaYg8VERGRrqj4mS96NbGHioiIiEhLbFARERERaYlDfkRERDrCdaj0B3uoiIiIiLTEHioiIiId4bIJ+oN3moiIiEhL7KEiIiLSEc6h0h/soSIiIiLSEhtURERERFrikB8REZGOcFK6/uCdriIXFxdIJBK1W3h4OACoPb5p0yZFWYIgYOXKlejQoQMsLS1hY2ODtm3bIi4uDg8ePFDku337NiZNmgRnZ2eYmJjAyckJQ4cOxeXLl1XGGB0dDUNDQyxatEjp2OrVq2FjY1OtrwkREZG+Yg9VFR06dAglJSUAgIyMDISEhCAnJwcymQwAYGZmpsiblJSEoKAg0fnPNmb+9a9/YevWrZg1axaWLl2KunXr4o8//kBcXBxcXFzQp08f3L59Gx07doSJiQmWL1+O5s2b4+LFi5g1axbatWuHzMxMuLm5iepITEzERx99hMTEREybNk1HrwQREanDSen6gw0qDSQnJyMqKgpnz56Fubk5WrVqhR07dsDCwgIAYGdnBwBwcHBQ2etjY2MDuVyusuxvv/0W69evx/bt2/Huu+8q0l1cXPDOO++gsLAQADBz5kxcu3YNZ8+eVZTVqFEj7N69G40bN8bYsWOxa9cuxfm//PILHj58iHnz5mHt2rXIyMhA586dq+X1ICIiIjEO+VUgNzcXYWFhGDp0KLKzs5Geno7g4GAIglAt5a9fvx6enp6ixlQZiUQCa2trlJaWYtOmTRg4cKBSw8zMzAxjxozB7t27cfv2bUV6QkICwsLCYGxsjLCwMCQkJFRLvERERKSMPVQVyM3NRXFxMYKDg+Hs7AwA8Pb2rlQZYWFhMDQ0FKWdOnUKjRo1wpkzZ+Dp6Vnu+fn5+SgoKICXl5fK415eXhAEAWfPnkX79u1RWFiI5ORkZGZmAgAGDRqEN954A4sXL4alpWWlYicioqrjkJ/+YIOqAj4+PvDz84O3tzcCAwMREBCA0NBQ2NraalxGbGws/P39RWlOTk4AUKmeLk3zbty4Ee7u7vDx8QEAtGzZEs7Ozti8eTOGDRumcX3PKioqQlFRkVKaVCqtUnlERESvEg75VcDQ0BCpqanYtWsXmjVrhvj4eHh6euLChQsalyGXy+Hh4SHajIyetmWbNGmCv/76q9zz69atCxsbG2RnZ6s8np2dDYlEAg8PDwBPh/tOnjwJIyMjxXbq1CkkJiZqHPPzoqOjYW1tLdqWL19e5fKIiPSCgUHNbfRC8RXXgEQiga+vL6KionD06FGYmJhg27Zt1VL2+++/j9OnT2PHjh1KxwRBwN27d2FgYIB+/fphw4YNyMvLE+V5+PAhli1bhsDAQNjZ2eH48eP4/fffkZ6ejmPHjim29PR0ZGZmVth4UycyMhJ3794VbaNGjapSWURERK8aDvlVICsrC2lpaQgICICDgwOysrKQn5+vdj6TKgUFBUoNISsrK1hYWKBfv37Ytm0bwsLCMGvWLAQEBKBu3bo4fvw4YmNjMX78ePTp0wcLFy5EWloaevTogc8++wwtWrTAhQsXMGvWLDx58gRffvklgKe9U+3bt0eXLl2U4mjXrh0SEhIU61KVlJTg2LFjojxSqVTltUmlUqXhvZsc7iMiKpdEwjlU+oINqgrIZDLs378fcXFxKCwshLOzM2JiYtCzZ0+Ny4iIiFBKi46OxowZMyCRSLBhwwasXLkSiYmJWLBgAYyMjNC4cWMMHjwYgYGBAAB7e3v89ttvmDdvHkaOHIm8vDzY2dmhZ8+eWLduHRo1aoTHjx9j3bp1mD59uso4QkJCEBMTg4ULFwIA/vnnH7Rq1UqUx93dHWfPntX42oiIiAiQCNX1/D/pnfPnztV0CBqTSCRw/d/CpxfOn6+2ZS90hfHqXm2LmfG+GG7u7tVaXv4s5T+oX5S6nyTVWN36iD1UREREOsLf8tMfvNNEREREWmIPFRERkY5wYU/9wR4qIiIiIi2xQUVERESkJQ75ERER6QonpesN3mkiIiIiLbGHioiISEc4KV1/sIeKiIiISEvsoSIiItIRiYT9FvqCd5qIiIhIS2xQEREREWmJQ35ERES6wknpeoM9VERERERaYg8VERGRjki4sKfe4J0mIiIi0hIbVERERERa4pAfERGRjnCldP3BHioiIiIiLbGHioiISFe4Urre4J2ugIuLCyQSidotPDwcANQe37RpEwAgPT1dbZ68vDwAwNy5c9GyZUu1sXTr1k3l+aNGjRLl27dvH9566y3Y29vD3NwczZo1w9SpU3H16lWNYyEiIiLNsYeqAocOHUJJSQkAICMjAyEhIcjJyYFMJgMAmJmZKfImJSUhKChIdL6NjY1o/9lzyzg4OGgcz/DhwzFv3jxRmrm5ueL/V6xYgTFjxmDIkCH47rvv4OLigsuXL2Pt2rWIiYnBF198UW2xEBFR+TiHSn+wQfWM5ORkREVF4ezZszA3N0erVq2wY8cOWFhYAADs7OwAPG10PN9QAp42nuRyebl1qDtXU+bm5mrruHLlCiZMmIAJEyYgNjZWke7i4oIuXbqgoKCgWmMhIiKip9ig+p/c3FyEhYXhs88+Q9++fXHv3j0cOHAAgiDUdGga27JlCx4/foyPPvpI5XE2noiIiHSDDar/yc3NRXFxMYKDg+Hs7AwA8Pb2rlQZYWFhMDQ0FKWdOnUKjRo1Uuw3aNBAdNzZ2RknT57UuI5ly5bh66+/FqWtWLECAwcOxJkzZyCTyVCvXj2NyqpMLEVFRSgqKlJKk0qlGsdORKR3uFK63mCD6n98fHzg5+cHb29vBAYGIiAgAKGhobC1tdW4jNjYWPj7+4vSnJycRPsHDhyAlZWVYt/Y2LhScQ4cOBAzZ84UpTk6OgIABEGARKL5eH1lYomOjkZUVJQobcL48Zg4caLG9REREb2q2KD6H0NDQ6SmpiIjIwN79uxBfHw8Zs6ciaysLLi6umpUhlwuh4eHR7l5XF1dtRp6s7a2VltHkyZNcPfuXeTm5mrUS1WZWCIjIzFlyhRR2tUrVzQ6l4hIX1Xmj1yq3dgX+QyJRAJfX19ERUXh6NGjMDExwbZt22o6LI2FhobCxMQEn332mcrjz09KrwypVAqZTCbaONxHRET0FHuo/icrKwtpaWkICAiAg4MDsrKykJ+fDy8vL43LKCgoUFrHycrKSvGUIADcuHEDjx49EuWxt7dXDLc9fPgQx44dUyrD3d0dAPDgwQOlOqRSKWxtbdGwYUPExsZi3LhxKCwsxODBg+Hi4oIrV65g7dq1sLS0RExMjMaxEBERkWbYoPofmUyG/fv3Iy4uDoWFhXB2dkZMTAx69uypcRkRERFKadHR0ZgxY4Zi39PTUylPZmYmOnbsCAA4ffo0WrVqJTru5+eHvXv3AgBWrVqFVatWiY4HBgYiJSUFADBmzBg0adIEn3/+Ofr27YuHDx/CxcUFvXv3VhqyqygWIiLSEiel6w2JUJvWBaCXyvlz52o6BI1JJBK4urkBAC6cP//SL4fBeHWvtsXMeF8Mt/+NBlSXe/HTqrW8yrAav6jG6tZH7KEiIiLSEa6Urj/YF0lERESkJTaoiIiIiLTEIT8iIiJdkbDfQl/wThMRERFpiT1UREREusJJ6XqDPVRERESEL7/8Ei4uLjA1NUWHDh1w8ODBcvNv2bIFTZs2hampKby9vfHTTz+JjoeHh0MikYi2oKAgUZ7bt29j4MCBkMlksLGxwbBhw/DPP/9U+7W9CGxQERER6YhEYlBjW2Vs3rwZU6ZMwZw5c3DkyBH4+PggMDAQN27cUJk/IyMDYWFhGDZsGI4ePYo+ffqgT58+OHHihChfUFAQcnNzFdvGjRtFxwcOHIiTJ08iNTUVP/zwA/bv348RI0ZU7kV+SbBBRUREpOe++OILDB8+HBEREWjWrBmWL18Oc3NzJCYmqsy/ePFiBAUFYdq0afDy8sL8+fPRunVrLF26VJRPKpVCLpcrNltbW8Wx7OxspKSk4Ouvv0aHDh3w+uuvIz4+Hps2bcK1a9d0er26wAYVERHRK6ioqAiFhYWiraioSCnf48ePcfjwYfj7+yvSDAwM4O/vj8zMTJVlZ2ZmivIDT38G7fn86enpcHBwgKenJ0aPHo1bt26JyrCxsUHbtm0Vaf7+/jAwMEBWVlaVrrkmsUFFRESkKwaSGtuio6NhbW0t2qKjo5VCvHnzJkpKSuDo6ChKd3R0RF5ensrLysvLqzB/UFAQ1q5di7S0NPznP//BL7/8gp49e6KkpERRhoODg6gMIyMj2NnZqa33Zcan/IiIiF5BkZGRmDJliihNKpW+sPoHDBig+H9vb2+89tprcHd3R3p6Ovz8/F5YHC8KG1REREQ6IjGouYEgqVSqUQOqTp06MDQ0xPXr10Xp169fh1wuV3mOXC6vVH4AcHNzQ506dXD27Fn4+flBLpcrTXovLi7G7du3yy3nZcUhPyIiIj1mYmKCNm3aIC0tTZFWWlqKtLQ0dOrUSeU5nTp1EuUHgNTUVLX5AeDKlSu4desW6tWrpyijoKAAhw8fVuT5+eefUVpaig4dOmhzSTWCDSoiIiI9N2XKFKxatQpr1qxBdnY2Ro8ejfv37yMiIgIAMHjwYERGRiryT5w4ESkpKYiJicFff/2FuXPn4vfff8e4ceMAAP/88w+mTZuG3377DRcvXkRaWhreffddeHh4IDAwEADg5eWFoKAgDB8+HAcPHsSvv/6KcePGYcCAAXBycnrxL4KWOORHRESkK5LasVJ6//79kZ+fj9mzZyMvLw8tW7ZESkqKYuL55cuXYfDM8GXnzp2xYcMGzJo1Cx9//DEaN26M7du3o0WLFgAAQ0ND/Pnnn1izZg0KCgrg5OSEgIAAzJ8/XzQMuX79eowbNw5+fn4wMDBASEgIlixZ8mIvvpqwQUVEREQYN26coofpeenp6Upp7733Ht577z2V+c3MzLB79+4K67Szs8OGDRsqFefLig0qIiIiXanBSen0YvFOExEREWmJPVRERES6UkvmUJH2XqkeKhcXF6Vftn52Cw8PBwC1xzdt2gTg6Vixujxlq7fOnTsXLVu2VBtLt27dVJ4/atQoRZ5n0y0sLNC4cWOEh4eLHiF9Np6CgoJy95s3b65YgbaMjY0NVq9erfI1MjMzg4uLC/r164eff/65Cq84ERERAa9Yg+rQoUOKX7T+7rvvAAA5OTmKtMWLFyvyJiUliX4BOzc3F3369BGV9+y5Zdvzy+SXZ/jw4Urnf/bZZ6I8ZXGcPHkSX375Jf755x906NABa9eurfT1nz9/XqPz5s2bh9zcXOTk5GDt2rWwsbGBv78/FixYUOk6iYiIqBYP+SUnJyMqKgpnz56Fubk5WrVqhR07dsDCwgLA0ycHAMDBwQE2NjZK59vY2FS4Equ6czVlbm5eYR3PxuHi4oKAgAAMGTIE48aNw9tvvy36Ze6KjB8/HnPmzMH7779f7uq4VlZWijobNWqELl26oF69epg9ezZCQ0Ph6empcZ1ERKReTa6UTi9WrbzTubm5CAsLw9ChQ5GdnY309HQEBwdDEISaDq1aTJ48Gffu3UNqamqlzps0aRKKi4sRHx9f6TonTpwIQRCwY8eOSp9LRESk72ptg6q4uBjBwcFwcXGBt7c3xowZA0tLS43LCAsLg6WlpWi7fPmyKE+DBg1Ex5s3b16pOJctW6ZUx/r16ys8r2nTpgCAixcvVqo+c3NzzJkzB9HR0bh7926lzrWzs4ODg4PaOouKilBYWCjaioqKKlUHEZHekRjU3EYvVK0c8vPx8YGfnx+8vb0RGBiIgIAAhIaGVmp4LDY2Fv7+/qK055e6P3DgAKysrBT7xsbGlYpz4MCBmDlzpiitbNXZ8pT1tEmq8HTIsGHDEBMTg//85z9YuHBhpc4VBEFtndHR0YiKihKlTRg/HhMnTqx0jERERK+aWtmgMjQ0RGpqKjIyMrBnzx7Ex8dj5syZyMrKgqurq0ZlyOVyeHh4lJvH1dVVqzlU1tbWFdahSnZ2tqL+yjIyMsKCBQsQHh6udsVbVW7duoX8/Hy1dUZGRmLKlCmitKtXrlQ6PiIioldRre0TlEgk8PX1RVRUFI4ePQoTExNs27atpsOqFnFxcZDJZEo9aJp677330Lx5c6UepfIsXrwYBgYGSk86lpFKpZDJZKKtvInvREQEwEBScxu9ULWyhyorKwtpaWkICAiAg4MDsrKykJ+fDy8vL43LKCgoUKwpVcbKykrxlCAA3LhxA48ePRLlsbe3Vwz9PXz4EMeOHVMqw93dHQDw4MEDpTqkUqloaLIsjqKiIpw+fRorVqzA9u3bFcsZVNWnn36q+EXv5927dw95eXl48uQJLly4gHXr1uHrr79GdHR0lXrUiIiI9F2tbFDJZDLs378fcXFxKCwshLOzM2JiYtCzZ0+Ny4iIiFBKi46OxowZMxT7qpYPyMzMRMeOHQEAp0+fRqtWrUTH/fz8sHfvXgDAqlWrsGrVKtHxwMBApKSkKMVhamqK+vXr4/XXX8fBgwfRunVrja9Fle7du6N79+7Ys2eP0rHZs2dj9uzZMDExgVwuR8eOHZGWloY333xTqzqJiEhMwsnhekMivCprDdALd/7cuZoOQWMSiQSubm4AgAvnz7/0S2wwXt2rbTEz3hfD7X8jDNXl0cb/VGt5lWEaNr3G6tZHtbKHioiIqFbgXCa9wb5IIiIiIi2xQUVERESkJQ75ERER6QonpesN3mkiIiIiLbGHioiISFeq8BNiVDuxh4qIiIhIS2xQEREREWmJQ35ERES6YsB+C33BO01ERESkJfZQERER6QqXTdAbvNNEREREWmIPFRERka7wt/z0BnuoiIiIiLTEBhURERGRljjkR0REpCuclK43eKeJiIiItMQeKiIiIl3hb/npDfZQEREREWmp1jaoXFxcIJFI1G7h4eEAoPb4pk2bAADp6elq8+Tl5QEA5s6di5YtW6qNpVu3birPHzVqlCLPs+kWFhZo3LgxwsPDcfjwYVFZZfEUFBQo0kpKShAbGwtvb2+YmprC1tYWPXv2xK+//lphDGVbt27dFK9bXFyc0jVUdI1ERESkXq0d8jt06BBKSkoAABkZGQgJCUFOTg5kMhkAwMzMTJE3KSkJQUFBovNtbGxE+8+eW8bBwUHjeIYPH4558+aJ0szNzUX7ZXE8evQIp0+fxsqVK9GhQwckJiZi8ODBKssVBAEDBgzA3r17sWjRIvj5+aGwsBBffvklunXrhi1btqBPnz7YunUrHj9+DAD4+++/0b59e+zduxfNmzcHAJiYmGh8LUREVE34W356o1Y0qJKTkxEVFYWzZ8/C3NwcrVq1wo4dO2BhYQEAsLOzA/C0AfR8Qwl42niSy+Xl1qHuXE2Zm5tXWMezcbi4uCAgIABDhgzBuHHj8Pbbb8PW1lbpnG+//RbJycnYuXMn3n77bUX6ypUrcevWLXzwwQfo0aOH4jUAgEePHgEA7O3tK4yJiIiItPfSN51zc3MRFhaGoUOHIjs7G+np6QgODoYgCDUdWrWYPHky7t27h9TUVJXHN2zYgCZNmogaU2WmTp2KW7duqT2XiIhqmERScxu9ULWiQVVcXIzg4GC4uLjA29sbY8aMgaWlpcZlhIWFwdLSUrRdvnxZlKdBgwai42VDZZpatmyZUh3r16+v8LymTZsCAC5evKjy+OnTp+Hl5aXyWFn66dOnKxXr9OnTlWJduHBhpcogIiKi//fSD/n5+PjAz88P3t7eCAwMREBAAEJDQ1UOj6kTGxsLf39/UZqTk5No/8CBA7CyslLsGxsbVyrOgQMHYubMmaI0R0fHCs8r62mTlPPXRHX3xk2bNk0xab/MkiVLsH//frXnFBUVoaioSClNKpVWa2xERK8ULuypN176BpWhoSFSU1ORkZGBPXv2ID4+HjNnzkRWVhZcXV01KkMul8PDw6PcPK6urlrNobK2tq6wDlWys7MV9avSpEkTRR515zZp0qRSddapU0cp1mfnYKkSHR2NqKgoUdqE8eMxceLEStVNRET0KqoVTWeJRAJfX19ERUXh6NGjMDExwbZt22o6rGoRFxcHmUym1INWZsCAAThz5gy+//57pWMxMTGwt7dHjx49dB0mIiMjcffuXdH27LIQRERE+uyl76HKyspCWloaAgIC4ODggKysLOTn56udV6RKQUGBYk2pMlZWVoqnBAHgxo0biqfjytjb2yuG/h4+fIhjx44pleHu7g4AePDggVIdUqlUNDRZFkdRURFOnz6NFStWYPv27Vi7dq3a3rEBAwZgy5YtGDJkiNKyCTt37sSWLVtE16ErUqlUaXjvJof7iIjKx2UT9MZL36CSyWTYv38/4uLiUFhYCGdnZ8TExKBnz54alxEREaGUFh0djRkzZij2PT09lfJkZmaiY8eOAJ5O/G7VqpXouJ+fH/bu3QsAWLVqFVatWiU6HhgYiJSUFKU4TE1NUb9+fbz++us4ePAgWrdurTZ2iUSCb7/9FnFxcYiNjcWYMWNgamqKTp06IT09Hb6+vhVdPhEREemYRHhV1h+gF+78uXM1HYLGJBIJXN3cAAAXzp9/6ZfdYLy6V9tiZrwvhtv/Rh2qy6PdCdVaXmWYBg6rsbr1EfsiiYiIiLTEBhURERGRll76OVRERES1Fteh0hu800RERERaYg8VERGRrvA39fQGe6iIiIiItMQeKiIiIl3hwp56g3eaiIiISEtsUBERERFpiUN+REREOiJwUrreYA8VERERkZbYQ0VERKQrXNhTb/BOExEREWmJDSoiIiIiLXHIj4iISFc45Kc3eKeJiIiItMQeKiIiIh3hsgn6gz1URERERFpig4qIiIhISxzyIyIi0hVOStcbvNP/4+LiAolEonYLDw8HALXHN23aBABIT09XmycvLw8AMHfuXLRs2VJtLN26dVN5/qhRoxR5JBIJtm/fLto3NTXFpUuXRGX16dNHETsAhIeHK8ozNjaGo6MjevTogcTERJSWlmr3IhIREekp9lD9z6FDh1BSUgIAyMjIQEhICHJyciCTyQAAZmZmirxJSUkICgoSnW9jYyPaf/bcMg4ODhrHM3z4cMybN0+UZm5uXu45EokEs2fPxpo1a8rNFxQUhKSkJJSUlOD69etISUnBxIkTkZycjJ07d8LIiG8LIqJqwUnpekMve6iSk5Ph7e0NMzMz2Nvbw9/fH+bm5pDL5ZDL5bCzswPwtAFUlmZtba0438bGRpFetpmamorqePbcss3AQPOX+9l4yrbnG2jPGzduHNatW4cTJ06Um08qlUIul6N+/fpo3bo1Pv74Y+zYsQO7du3C6tWrNY6RiIheHV9++SVcXFxgamqKDh064ODBg+Xm37JlC5o2bQpTU1N4e3vjp59+Uhx78uQJpk+fDm9vb1hYWMDJyQmDBw/GtWvXRGWoGh369NNPdXJ9uqZ3Darc3FyEhYVh6NChyM7ORnp6OoKDgyEIQk2HpjVfX1/07t0bM2bMqPS53bt3h4+PD7Zu3aqDyIiI9JSBQc1tlbB582ZMmTIFc+bMwZEjR+Dj44PAwEDcuHFDZf6MjAyEhYVh2LBhOHr0KPr06YM+ffoo/qB/8OABjhw5gn//+984cuQItm7dipycHLzzzjtKZc2bNw+5ubmKbfz48ZV/nV8CetmgKi4uRnBwMFxcXODt7Y0xY8bA0tJS4zLCwsJgaWkp2i5fvizK06BBA9Hx5s2bVyrOZcuWKdWxfv36Cs+Ljo5GSkoKDhw4UKn6AKBp06a4ePFipc8jIqLa7YsvvsDw4cMRERGBZs2aYfny5TA3N0diYqLK/IsXL0ZQUBCmTZsGLy8vzJ8/H61bt8bSpUsBANbW1khNTUW/fv3g6emJjh07YunSpTh8+LDSv5dWVlai0RgLCwudX68u6N1kGR8fH/j5+cHb2xuBgYEICAhAaGgobG1tNS4jNjYW/v7+ojQnJyfR/oEDB2BlZaXYNzY2rlScAwcOxMyZM0Vpjo6OFZ7XrFkzDB48GDNmzMCvv/5aqToFQYBEzXh/UVERioqKlNKkUmml6iAiohdD1fe2VCpV+t5+/PgxDh8+jMjISEWagYEB/P39kZmZqbLszMxMTJkyRZQWGBgoeljqeXfv3oVEIlGac/zpp59i/vz5aNSoEd5//31Mnjy5Vs7l1bseKkNDQ6SmpmLXrl1o1qwZ4uPj4enpiQsXLmhchlwuh4eHh2h7/ua7urqKjjs7O1cqTmtra6U6nm2glScqKgpHjhwp942tSnZ2NlxdXVUei46OhrW1tWhbvnx5pconItI3gkRSY5uq7+3o6GilGG/evImSkhKlP9odHR0VT6c/Ly8vr1L5Hz16hOnTpyMsLEw0H3jChAnYtGkT9u3bh5EjR2LhwoX46KOPKvsyvxRqXxOwGkgkEvj6+sLX1xezZ8+Gs7Mztm3bptTarq0aNmyIcePG4eOPP4a7u7tG5/z88884fvw4Jk+erPJ4ZGSk0utz9coVrWMlIiLdUPW9XROjCk+ePEG/fv0gCAK++uor0bFn43vttddgYmKCkSNHIjo6utaNgOhdgyorKwtpaWkICAiAg4MDsrKykJ+fDy8vL43LKCgoUGqFW1lZicZ9b9y4gUePHony2NvbK4b+Hj58iGPHjimVUdYAevDggVIdUqlU46HJyMhIrFq1ChcuXED//v1Fx4qKipCXlydaNiE6Ohq9e/fG4MGDVZanqpv4Zi17sxMRvXA1uLCnqu9tVerUqQNDQ0Ncv35dlH79+nXI5XKV58jlco3ylzWmLl26hJ9//rnCp9U7dOiA4uJiXLx4EZ6enhXG/jLRuyE/mUyG/fv346233kKTJk0wa9YsxMTEoGfPnhqXERERgXr16om2+Ph4UR5PT0+lPIcPH1YcP336NFq1aiXaRo4cqTi+atUqpfPDwsI0jtHOzg7Tp09XatQBQEpKCurVqwcXFxcEBQVh3759WLJkCXbs2AFDQ0ON6yAiotrPxMQEbdq0QVpamiKttLQUaWlp6NSpk8pzOnXqJMoPAKmpqaL8ZY2pM2fOYO/evbC3t68wlmPHjsHAwKBS6za+LCTCq7BeANWI8+fO1XQIGpNIJHB1cwMAXDh//qVfJoPx6l5ti5nxvhhuGk6T0NT9zO3VWl5lWHTqo3HezZs3Y8iQIVixYgXat2+PuLg4fPvtt/jrr7/g6OiIwYMHo379+oo5WBkZGejatSs+/fRT9OrVC5s2bcLChQtx5MgRtGjRAk+ePEFoaCiOHDmCH374QTTfys7ODiYmJsjMzERWVhbefPNNWFlZITMzE5MnT0bPnj0rXKD6ZaR3Q35EREQvilBLfsuvf//+yM/Px+zZs5GXl4eWLVsiJSVF0RC6fPmyaHHqzp07Y8OGDZg1axY+/vhjNG7cGNu3b0eLFi0AAFevXsXOnTsBQOmn1vbt24du3bpBKpVi06ZNmDt3LoqKiuDq6orJkyfX2vnM7KGiKmMPle4wXt2rbTEz3hejunuo/vltZ7WWVxmWHZUX0STdYQ8VERGRrvC3/PRG7eiLJCIiInqJsYeKiIhIR2rLHCrSHu80ERERkZbYoCIiIiLSEof8iIiIdIWT0vUGe6iIiIiItMQeKiIiIl3hpHS9wTtNREREpCU2qIiIiIi0xCE/IiIiHRE4KV1vsIeKiIiISEvsoSIiItIVTkrXG7zTRERERFpiDxUREZGOCOAcKn3BHioiIiIiLbFBRURERKQlDvkRERHpiMBJ6XpDL++0i4sLJBKJ2i08PBwA1B7ftGkTACA9PV1tnry8PADA3Llz0bJlS7WxdOvWTeX5o0aNEuX74Ycf0LVrV1hZWcHc3Bzt2rXD6tWrFcfnzp1b7jVJ/rcWSnh4OPr06aMUR9m1FBQUVPl1JSIi0ld62UN16NAhlJSUAAAyMjIQEhKCnJwcyGQyAICZmZkib1JSEoKCgkTn29jYiPafPbeMg4ODxvEMHz4c8+bNE6WZm5sr/j8+Ph6TJk3C9OnT8dVXX8HExAQ7duzAqFGjcOLECXz++ef48MMPRY2wdu3aYcSIERg+fLjGcRARUTVjD5XeeOUbVMnJyYiKisLZs2dhbm6OVq1aYceOHbCwsAAA2NnZAXjaAHq+oQQ8bTzJ5fJy61B3rqbMzc3V1vH3339j6tSpmDRpEhYuXKhInzp1KkxMTDBhwgS899576NChAywtLRXHDQ0NYWVlVWHsREREpL1Xuumcm5uLsLAwDB06FNnZ2UhPT0dwcDAEQajp0DSWnJyMJ0+e4MMPP1Q6NnLkSFhaWmLjxo01EBkRERGVeaV7qHJzc1FcXIzg4GA4OzsDALy9vStVRlhYGAwNDUVpp06dQqNGjRT7DRo0EB13dnbGyZMnNa5j2bJl+Prrr0VpK1aswMCBA3H69GlYW1ujXr16SueZmJjAzc0Np0+f1rgu4Ol8rGd7swAohkCJiKj68Lf89Mcr3aDy8fGBn58fvL29ERgYiICAAISGhsLW1lbjMmJjY+Hv7y9Kc3JyEu0fOHAAVlZWin1jY+NKxTlw4EDMnDlTlObo6FipMirjzTffxFdffSVKy8rKwqBBg9SeU1RUhKKiIqU0qVSqkxiJiIhqk1e6QWVoaIjU1FRkZGRgz549iI+Px8yZM5GVlQVXV1eNypDL5fDw8Cg3j6urq1ZzqKytrdXW0aRJE9y9exfXrl1Tasg9fvwY586dw5tvvlmp+iwsLJTqu3LlSrnnREdHIyoqSpQ2Yfx4TJw4sVJ1ExHpEy6boD9e+TstkUjg6+uLqKgoHD16FCYmJti2bVtNh6WxkJAQGBsbIyYmRunY8uXLcf/+fYSFhek8jsjISNy9e1e0Pb+0AxERkb56pXuosrKykJaWhoCAADg4OCArKwv5+fnw8vLSuIyCggLFmlJlrKysFE8JAsCNGzfw6NEjUR57e3vF0N/Dhw9x7NgxpTLc3d0BAA8ePFCqQyqVwtbWFo0aNcJnn32GqVOnwtTUFP/6179gbGyMHTt24OOPP8bUqVPRoUMHja+nqqRSqdLw3k0O9xERlY9zqPTGK92gkslk2L9/P+Li4lBYWAhnZ2fExMSgZ8+eGpcRERGhlBYdHY0ZM2Yo9j09PZXyZGZmomPHjgCA06dPo1WrVqLjfn5+2Lt3LwBg1apVWLVqleh4YGAgUlJSAACTJk2Cm5sbPv/8cyxevBglJSVo3rw5vvrqK5XxERER0YslEWrTGgL0Ujl/7lxNh6AxiUQCVzc3AMCF8+df+qUzGK/u1baYGe+L4fa/kYPqcvv4f6u1vMqw8369xurWR690DxUREVFN4qR0/cE7TURERKQl9lARERHpiABOStcX7KEiIiIi0hIbVERERERa4pAfERGRjnBSuv7gnSYiIiLSEnuoiIiIdIUrpesN9lARERERaYk9VERERDoisN9Cb/BOExEREWmJDSoiIiIiLXHIj4iISEcETkrXG+yhIiIiItISe6iIiIh0hAt76g/eaSIiIiItsUFFREREpCUO+REREemIAE5K1xfsoSIiIiLSEnuoiIiIdIST0vWH3t9pFxcXSCQStVt4eDgAqD2+adMmAEB6erraPHl5eQCAuXPnomXLlmpj6datm8rzR40ahdWrV5cbp0QiwcWLFzF37lzFvqGhIRo2bIgRI0bg9u3bSvU9fPgQdnZ2qFOnDoqKiqr9tSUiItIXet9DdejQIZSUlAAAMjIyEBISgpycHMhkMgCAmZmZIm9SUhKCgoJE59vY2Ij2nz23jIODg8bxDB8+HPPmzROlmZubw9jYWFR3cHAwWrRoIcpbt25dAEDz5s2xd+9elJSUIDs7G0OHDsXdu3exefNmUbnfffcdmjdvDkEQsH37dvTv31/jOImIqGJc2FN/6FWDKjk5GVFRUTh79izMzc3RqlUr7NixAxYWFgAAOzs7AE8bQM83lICnjSe5XF5uHerO1ZS5ubnaOp5t3JmYmKjNa2RkpEivX78+3nvvPSQlJSnlS0hIwKBBgyAIAhISEtigIiIiqiK9aVDl5uYiLCwMn332Gfr27Yt79+7hwIEDEAShpkPTqYsXL2L37t0wMTERpZ87dw6ZmZnYunUrBEHA5MmTcenSJTg7O9dQpERERLWXXjWoiouLERwcrGg0eHt7V6qMsLAwGBoaitJOnTqFRo0aKfYbNGggOu7s7IyTJ09qXMeyZcvw9ddfi9JWrFiBgQMHalzG8ePHYWlpiZKSEjx69AgA8MUXX4jyJCYmomfPnrC1tQUABAYGIikpCXPnzlVZZlFRkdI8q6KiIkilUo3jIiLSN1w2QX/oTYPKx8cHfn5+8Pb2RmBgIAICAhAaGqpoUGgiNjYW/v7+ojQnJyfR/oEDB2BlZaXYNzY2rlScAwcOxMyZM0Vpjo6OlSrD09MTO3fuxKNHj7Bu3TocO3YM48ePVxwvKSnBmjVrsHjxYkXaoEGD8OGHH2L27NkwMFB+ViE6OhpRUVGitAnjx2PixImVio2IiOhVpDcNKkNDQ6SmpiIjIwN79uxBfHw8Zs6ciaysLLi6umpUhlwuh4eHR7l5XF1dtZpDZW1tXWEdFTExMVGU8emnn6JXr16IiorC/PnzAQC7d+/G1atXleZMlZSUIC0tDT169FAqMzIyElOmTBGlXb1yRas4iYhedVw2QX/o1Z2WSCTw9fVFVFQUjh49ChMTE2zbtq2mw9K5WbNm4fPPP8e1a9cAPJ2MPmDAABw7dky0DRgwAAkJCSrLkEqlkMlkoo3DfURERE/pTQ9VVlYW0tLSEBAQAAcHB2RlZSE/Px9eXl4al1FQUKBYU6qMlZWV4ilBALhx44Zi3lIZe3t7xdDfw4cPcezYMaUy3N3dAQAPHjxQqkMqlVZqaPJ5nTp1wmuvvYaFCxdizpw5+P7777Fz5060aNFClG/w4MHo27cvbt++rXjikYiIiCqmNw0qmUyG/fv3Iy4uDoWFhXB2dkZMTAx69uypcRkRERFKadHR0ZgxY4Zi39PTUylPZmYmOnbsCAA4ffo0WrVqJTru5+eHvXv3AgBWrVqFVatWiY4HBgYiJSVF4zhVmTx5MsLDw1G3bl1YWFjAz89PKY+fnx/MzMywbt06TJgwQav6iIiIk9L1iUR41dcNIJ05f+5cTYegMYlEAlc3NwDAhfPnX/rlMhiv7tW2mBnvi+H2v9GC6nL5THa1llcZjRprPgJD2quWOVTffvstHj9+rNi/cuUKSktLFfsPHjzAZ599Vh1VERER1RqCxKDGNnqxquUVDwsLQ0FBgWK/WbNmuHjxomL/3r17iIyMrI6qiIiIiF461dKger4rt7Z07RIRERFVB72ZlE5ERPSicVK6/uAgKxEREZGWqq2Havfu3bC2tgYAlJaWIi0tDSdOnAAA0fwqIiIifcHJ4fqj2u70kCFD0KdPH/Tp0wcPHz7EyJEjFfvh4eHVVQ0RERHpwJdffgkXFxeYmpqiQ4cOOHjwYLn5t2zZgqZNm8LU1BTe3t746aefRMcFQcDs2bNRr149mJmZwd/fH2fOnBHluX37NgYOHAiZTAYbGxsMGzYM//zzT7Vf24tQLQ2q0tLSCreSkpLqqIqIiKjWECCpsa0yNm/ejClTpmDOnDk4cuQIfHx8EBgYiBs3bqjMn5GRgbCwMAwbNgxHjx5VdKCUjUwBwGeffYYlS5Zg+fLlyMrKgoWFBQIDA0W/JjJw4ECcPHkSqamp+OGHH7B//36MGDGiai92DauWBtXQoUNx79696iiKiIiIXrAvvvgCw4cPR0REBJo1a4bly5fD3NwciYmJKvMvXrwYQUFBmDZtGry8vDB//ny0bt0aS5cuBfC0dyouLg6zZs3Cu+++i9deew1r167FtWvXsH37dgBAdnY2UlJS8PXXX6NDhw54/fXXER8fj02bNil+e7Y2qZYG1Zo1a/Dw4cPqKIqIiIiqQVFREQoLC0VbUVGRUr7Hjx/j8OHD8Pf3V6QZGBjA398fmZmZKsvOzMwU5Qee/kxaWf4LFy4gLy9PlMfa2hodOnRQ5MnMzISNjQ3atm2ryOPv7w8DAwNkZWVV/cJriE7WoSIiIiJAkEhqbIuOjoa1tbVoi46OVorx5s2bKCkpgaOjoyjd0dEReXl5Kq8rLy+v3Pxl/60oj4ODg+i4kZER7Ozs1Nb7Mqu2p/zu3bsHU1PTcvPIZLLqqo6IiIjKERkZiSlTpojSpFJpDUXz6qu2BlWTJk3UHhMEARKJhBPTiYhIrwhCzS3sKZVKNWpA1alTB4aGhrh+/boo/fr165DL5SrPkcvl5eYv++/169dRr149UZ6WLVsq8jw/6b24uBi3b99WW+/LrNoaVMnJybCzs6uu4oiIiOgFMDExQZs2bZCWloY+ffoA+P/1JMeNG6fynE6dOiEtLQ2TJk1SpKWmpqJTp04AAFdXV8jlcqSlpSkaUIWFhcjKysLo0aMVZRQUFODw4cNo06YNAODnn39GaWkpOnTooJuL1aFqa1D5+voqjYUSERHRy2/KlCkYMmQI2rZti/bt2yMuLg73799HREQEAGDw4MGoX7++Yg7WxIkT0bVrV8TExKBXr17YtGkTfv/9d6xcuRIAIJFIMGnSJHzyySdo3LgxXF1d8e9//xtOTk6KRpuXlxeCgoIwfPhwLF++HE+ePMG4ceMwYMAAODk51cjroA3+lh8REZGOCLXkF9769++P/Px8zJ49G3l5eWjZsiVSUlIUk8ovX74MA4P/v5bOnTtjw4YNmDVrFj7++GM0btwY27dvR4sWLRR5PvroI9y/fx8jRoxAQUEBXn/9daSkpIjmW69fvx7jxo2Dn58fDAwMEBISgiVLlry4C69GEqEaHtFzdXXF77//DnNzcwiCAHNzcwDApUuXsG3bNnh5eSEwMFDrYOnlcv7cuZoOQWMSiQSubm4AgAvnz7/0T6YyXt2rbTEz3hfDzd29Wss7c+5StZZXGY3dnWusbn1ULT1UFy5cAAAEBAQgODgYo0aNQkFBATp06ABjY2PcvHkTX3zxhWLclIiISB9UdsVyqr2qtS/yyJEjeOONNwA8naTu6OiIS5cuYe3atbW2C4+IiIioItU6h+rBgwewsrICAOzZswfBwcEwMDBAx44dcelSzXV7EhER1QT2UOmPau2h8vDwwPbt2/H3339j9+7dCAgIAADcuHGDi3qWw8XFBRKJRO0WHh4OAGqPb9q0CQCQnp4OiUSCgoIClXXExcUBePrr3uPHj4enpyfMzMzQqFEjTJgwAXfv3n1BV0xERPRqqdYeqtmzZ+P999/H5MmT4efnp1iPYs+ePWjVqlV1VvVKOXTokGLR04yMDISEhCAnJ0fRCDUzM1PkTUpKQlBQkOh8GxubStV37do1XLt2DZ9//jmaNWuGS5cuYdSoUbh27RqSk5O1uxgiIiI9VK0NqtDQULz++uvIzc2Fj4+PIt3Pzw99+/atzqpqreTkZERFReHs2bMwNzdHq1atsGPHDlhYWACAYnFUBwcHlQ0lGxsbrVeQbdGiBb777jvFvru7OxYsWIBBgwahuLgYRkZcTYOIqDpwyE9/VPu/nHK5XOkf/Pbt21d3NbVSbm4uwsLC8Nlnn6Fv3764d+8eDhw48FI8Tnz37l3IZDI2poiIiKqA/3q+QLm5uSguLkZwcDCcnZ+uD+Lt7V2pMsLCwmBoaChKO3XqFBo1aqTYb9CggdJ5Dx48UFvmzZs3MX/+fIwYMUJtnqKiIhQVFSml8Yc2iYjUYw+V/mCD6gXy8fGBn58fvL29ERgYiICAAISGhsLW1lbjMmJjY+Hv7y9Ke36J/gMHDiietizTrVs3leUVFhaiV69eaNasGebOnau23ujoaERFRYnSJowfj4kTJ2ocOxER0auKDaoXyNDQEKmpqcjIyMCePXsQHx+PmTNnIisrC66urhqVIZfL4eHhUW4eV1dXpflXqoby7t27h6CgIFhZWWHbtm0wNjZWW2ZkZCSmTJkiSrt65YpGMRMREb3qasePDL1CJBIJfH19ERUVhaNHj8LExATbtm174XEUFhYiICAAJiYm2Llzp+i3lVSRSqWQyWSijcN9RETlEwRJjW30YrGH6gXKyspCWloaAgIC4ODggKysLOTn58PLy0vjMgoKCpCXlydKs7KyUjwlqImyxtSDBw+wbt06FBYWorCwEABQt25dpTlaREREVD42qF4gmUyG/fv3Iy4uDoWFhXB2dkZMTAx69uypcRkRERFKadHR0ZgxY4bGZRw5cgRZWVkAoDR8eOHCBbi4uGhcFhERqcdJ6fqDDaoXyMvLCykpKeXm6datm9plFCpaXqG8cy9evKhRPiIiIqo8NqiIiIh0hD1U+oOT0omIiIi0xAYVERERkZY45EdERKQjHPLTH+yhIiIiItISe6iIiIh0hAts6g/2UBERERFpiQ0qIiIiIi1xyI+IiEhHSjkpXW+wh4qIiIhIS+yhIiIi0hEum6A/2ENFREREpCX2UBEREekIl03QH+yhIiIiItISG1REREREWuKQHxERkY5wUrr+YA8VERERkZbYQ0VERKQjnJSuP9hDRURERKSlWt+gcnFxgUQiUbuFh4cDgNrjmzZtAgCkp6dDIpGgoKBAZR1xcXEV1vnpp58qnRsYGAhDQ0McOnRI6Vh4eLjiXGNjYzg6OqJHjx5ITExEaWlphTGoium3334TnTdp0iR069ZNsT937lxFnUZGRqhTpw66dOmCuLg4FBUVqXmViYiIqDy1fsjv0KFDKCkpAQBkZGQgJCQEOTk5kMlkAAAzMzNF3qSkJAQFBYnOt7GxqVK98+bNw/Dhw0VpVlZWov3Lly8jIyMD48aNQ2JiItq1a6dUTlBQEJKSklBSUoLr168jJSUFEydORHJyMnbu3AkjI81vkampKaZPn45ffvml3HzNmzfH3r17UVpailu3biE9PR2ffPIJvvnmG6SnpytdBxERVQ0npeuPWtVDlZycDG9vb5iZmcHe3h7+/v4wNzeHXC6HXC6HnZ0dAMDBwUGRZm1trTjfxsZGkV62mZqaVikWKysrpbIsLCxEeZKSktC7d2+MHj0aGzduxMOHD5XKkUqlkMvlqF+/Plq3bo2PP/4YO3bswK5du7B69epKxTRixAj89ttv+Omnn8rNZ2RkBLlcDicnJ3h7e2P8+PH45ZdfcOLECfznP/+pVJ1ERERUixpUubm5CAsLw9ChQ5GdnY309HQEBwdDEISaDk0lQRCQlJSEQYMGoWnTpvDw8EBycrJG53bv3h0+Pj7YunVrpep0dXXFqFGjEBkZqTRkWJGmTZuiZ8+ela6TiIjUEwRJjW30YtWqBlVxcTGCg4Ph4uICb29vjBkzBpaWlhqXERYWBktLS9F2+fJlUZ4GDRpUmAcApk+frpTvwIEDiuN79+7FgwcPEBgYCAAYNGgQEhISNI61adOmuHjxosb5y8yaNQsXLlzA+vXrK31uVeskIiLSd7VmDpWPjw/8/Pzg7e2NwMBABAQEIDQ0FLa2thqXERsbC39/f1Gak5OTaP/AgQNKc4iendRdZtq0aYoJ72Xq16+v+P/ExET0799fMQcqLCwM06ZNw7lz5+Du7l5hrIIgQCKp/F8YdevWxYcffojZs2ejf//+lTq3vDqLioqUJq0XFRVBKpVWOkYiIn1RubECqs1qTQ+VoaEhUlNTsWvXLjRr1gzx8fHw9PTEhQsXNC5DLpfDw8NDtD0/6dvV1bXCPABQp04dpXxlE+Bv376Nbdu2YdmyZTAyMoKRkRHq16+P4uJiJCYmahRrdnY2XF1dNb62Z02ZMgUPHz7EsmXLKnVeeXVGR0fD2tpatC1fvrxK8REREb1qak2DCni69IGvry+ioqJw9OhRmJiYYNu2bTUdlpL169ejQYMG+OOPP3Ds2DHFFhMTg9WrVyueSlTn559/xvHjxxESElKl+i0tLfHvf/8bCxYswL179zQ656+//kJKSoraOiMjI3H37l3RNmrUqCrFR0RE9KqpNUN+WVlZSEtLQ0BAABwcHJCVlYX8/Hx4eXlpXEZBQQHy8vJEaVZWVkpP52ni3r17SmWZm5tDJpMhISEBoaGhaNGiheh4w4YNERkZiZSUFPTq1QvA02GzvLw80bIJ0dHR6N27NwYPHlzpuMqMGDECsbGx2LBhAzp06CA6VlxcjLy8PKVlE1q2bIlp06apLE8qlSoN793kcB8RUbk4OVx/1JoeKplMhv379+Ott95CkyZNMGvWLMTExKBnz54alxEREYF69eqJtvj4+CrFM3v2bKWyPvroIxw+fBh//PGHyp4ea2tr+Pn5iSanp6SkoF69enBxcUFQUBD27duHJUuWYMeOHTA0NKxSbABgbGyM+fPn49GjR0rHTp48iXr16qFRo0bo1q0bvv32W0RGRuLAgQOVmuRPRERET0mEl3XdAXrpnT93rqZD0JhEIoGrmxsA4ML58y/tchtlGK/u1baYGe+L4abBQ0OVkZGt2bQLXejsxUWaX6Ra00NFRERE9LJig4qIiIhIS7VmUjoREVFtw0np+oM9VERERERaYg8VERGRjghgD5W+YA8VERERkZbYQ0VERKQjpbVjtQiqBuyhIiIiItISG1REREREWuKQHxERkY5wUrr+YA8VERERkZbYQ0VERKQjXNhTf7CHioiIiEhLbFARERERaYlDfkRERDoicB0qvcEeKiIiIiItsYeKiIhIR0q5bILeYA8VERERkZbYoCIiIiLSEof8iIiIdITrUOmPWtVD5eLiAolEonYLDw8HALXHN23aBABIT0+HRCJBQUGByjri4uIqrPPTTz9VOjcwMBCGhoY4dOiQ0rHw8HDFucbGxnB0dESPHj2QmJiI0tLScmMAgIyMDLz11luwtbWFqakpvL298cUXX6CkpAQAsHr16nJfG4lEgosXL2Lu3Llo2bKlUnwXL16ERCLBsWPH1N8AIiIiUqlW9VAdOnRI0YDIyMhASEgIcnJyIJPJAABmZmaKvElJSQgKChKdb2NjU6V6582bh+HDh4vSrKysRPuXL19GRkYGxo0bh8TERLRr106pnKCgICQlJaGkpATXr19HSkoKJk6ciOTkZOzcuRNGRqpvx7Zt29CvXz9ERERg3759sLGxwd69e/HRRx8hMzMT3377Lfr37y+63uDgYLRo0QLz5s1TpNWtW7dK109ERFXDZRP0x0vbQ5WcnAxvb2+YmZnB3t4e/v7+MDc3h1wuh1wuh52dHQDAwcFBkWZtba0438bGRpFetpmamlYpFisrK6WyLCwsRHmSkpLQu3dvjB49Ghs3bsTDhw+VypFKpZDL5ahfvz5at26Njz/+GDt27MCuXbuwevVqlXXfv38fw4cPxzvvvIOVK1eiZcuWcHFxwQcffIA1a9YgOTkZ3377LczMzETxmZiYiF4vuVwOQ0PDKl0/ERFRmdu3b2PgwIGQyWSwsbHBsGHD8M8//5R7zqNHjzB27FjY29vD0tISISEhuH79uuL4H3/8gbCwMDRs2BBmZmbw8vLC4sWLRWWUjS49v+Xl5enkOivrpWxQ5ebmIiwsDEOHDkV2djbS09MRHBwM4SVt6guCgKSkJAwaNAhNmzaFh4cHkpOTNTq3e/fu8PHxwdatW1Ue37NnD27duoUPP/xQ6djbb7+NJk2aYOPGjVrFT0REuiFAUmObrgwcOBAnT55EamoqfvjhB+zfvx8jRowo95zJkyfj+++/x5YtW/DLL7/g2rVrCA4OVhw/fPgwHBwcsG7dOpw8eRIzZ85EZGQkli5dqlRWTk4OcnNzFZuDg0O1X2NVvJRDfrm5uSguLkZwcDCcnZ0BAN7e3pUqIywsTKlH5tSpU2jUqJFiv0GDBkrnPXjwQClt+vTpmDVrliht165deOONNwAAe/fuxYMHDxAYGAgAGDRoEBISEvCvf/1Lo1ibNm2KP//8U+Wx06dPAwC8vLzUnluWR1PHjx+HpaWlKO1lbawSEdHLIzs7GykpKTh06BDatm0LAIiPj8dbb72Fzz//HE5OTkrn3L17FwkJCdiwYQO6d+8O4OmojpeXF3777Td07NgRQ4cOFZ3j5uaGzMxMbN26FePGjRMdc3BwqPIUHl16KRtUPj4+8PPzg7e3NwIDAxEQEIDQ0FDY2tpqXEZsbCz8/f1Fac/f6AMHDijNherWrZtSWdOmTVNMeC9Tv359xf8nJiaif//+ijlQYWFhmDZtGs6dOwd3d/cKYxUEARJJ+X9NVGeDx9PTEzt37hSlXb16VeW1lykqKkJRUZFSmlQqrba4iIio+qj63pZKpVp9b2dmZsLGxkbRmAIAf39/GBgYICsrC3379lU65/Dhw3jy5Ino3+SmTZuiUaNGyMzMRMeOHVXWdffuXcX0nme1bNkSRUVFaNGiBebOnQtfX98qX091eimH/AwNDZGamopdu3ahWbNmiI+Ph6enJy5cuKBxGXK5HB4eHqLt+Unfrq6uFeYBgDp16ijlK5sAf/v2bWzbtg3Lli2DkZERjIyMUL9+fRQXFyMxMVGjWLOzs+Hq6qryWJMmTRR51J1blkdTJiYmStdT1hOoTnR0NKytrUXb8uXLK1UvEZG+KRVqblP1vR0dHa3V9eTl5SkNsRkZGcHOzk7tXKa8vDyYmJgo9So5OjqqPScjIwObN28WDSXWq1cPy5cvx3fffYfvvvsODRs2RLdu3XDkyBGtrqm6vJQNKuDp0ge+vr6IiorC0aNHYWJigm3bttV0WErWr1+PBg0a4I8//sCxY8cUW0xMDFavXq14KlGdn3/+GcePH0dISIjK4wEBAbCzs0NMTIzSsZ07d+LMmTMICwurlmspT2RkJO7evSvaRo0apfN6iYioalR9b0dGRqrMO2PGjAqX3vnrr79eSNwnTpzAu+++izlz5iAgIECR7unpiZEjR6JNmzbo3LkzEhMT0blzZ8TGxr6QuCryUg75ZWVlIS0tDQEBAXBwcEBWVhby8/PVziNSpaCgQKnla2VlpfR0nibu3bunVJa5uTlkMhkSEhIQGhqKFi1aiI43bNgQkZGRSElJQa9evQA87X7Ny8sTLZsQHR2N3r17Y/DgwSrrtrCwwIoVKzBgwACMGDEC48aNg0wmQ1paGqZNm4bQ0FD069ev0tdUWaq6iW9yuI+IqFw1ubCnVGqi8fDe1KlTlaa2PM/NzQ1yuRw3btwQpRcXF+P27duQy+Uqz5PL5Xj8+DEKCgpEvVTXr19XOufUqVPw8/PDiBEjlOYuq9K+fXv897//rTDfi/BSNqhkMhn279+PuLg4FBYWwtnZGTExMejZs6fGZURERCilRUdHY8aMGZWOZ/bs2Zg9e7YobeTIkRg+fDj++OMPrFq1Sukca2tr+Pn5ISEhQdGgSklJQb169WBkZARbW1v4+PhgyZIlGDJkCAwM1HcWhoaGYt++fViwYAHeeOMNPHr0CI0bN8bMmTMxadKkCudfERERladu3boarVXYqVMnFBQU4PDhw2jTpg2ApyMtpaWl6NChg8pz2rRpA2NjY6SlpSlGY3JycnD58mV06tRJke/kyZPo3r07hgwZggULFmgU97Fjx1CvXj2N8uqaRODjXVRF58+dq+kQNCaRSODq5gYAuHD+/Ev/VCPj1b3aFjPjfTHcNHiQqDJ2HX1SreVVRs9Wxropt2dPXL9+HcuXL8eTJ08QERGBtm3bYsOGDQCePuTk5+eHtWvXon379gCA0aNH46effsLq1ashk8kwfvx4AE/nSgFPh/m6d++OwMBALFq0SFGXoaGhoqEXFxcHV1dXNG/eHI8ePcLXX3+N+Ph47NmzB35+fjq51sp4KXuoiIiIXgW1pB1ZKevXr8e4cePg5+cHAwMDhISEYMmSJYrjT548QU5OjmgZotjYWEXeoqIiBAYGYtmyZYrjycnJyM/Px7p167Bu3TpFurOzMy5evAgAePz4MaZOnYqrV6/C3Nwcr732Gvbu3Ys333xT9xetAfZQUZWxh0p3GK/u1baYGe+LUd09VD8dqbkeqrda66aHilRjDxUREZGOlOpwxXJ6uby0yyYQERER1RbsoSIiItKRWjLSSdWAPVREREREWmKDioiIiEhLHPIjIiLSkZpcKZ1eLPZQEREREWmJPVREREQ6UspJ6XqDPVREREREWmKDioiIiEhLHPIjIiLSEa5DpT/YQ0VERESkJfZQERER6YjA3/LTG+yhIiIiItISe6iIiIh0hMsm6A/2UBERERFpiQ0qIiIiIi1xyI+IiEhHuGyC/mAP1TNcXFwgkUjUbuHh4QCg9vimTZsAAOnp6ZBIJGjevDlKSkpEddjY2GD16tVKdUdHR8PQ0BCLFi1SGVteXh4mTpwIDw8PmJqawtHREb6+vvjqq6/w4MGDSpVXUlKCTz/9FE2bNoWZmRns7OzQoUMHfP3115V8xYiIiAhgD5XIoUOHFA2gjIwMhISEICcnBzKZDABgZmamyJuUlISgoCDR+TY2NqL98+fPY+3atYiIiKiw7sTERHz00UdITEzEtGnTlMrx9fWFjY0NFi5cCG9vb0ilUhw/fhwrV65E/fr18c4772hcXlRUFFasWIGlS5eibdu2KCwsxO+//447d+5UGCcREWmOPVT6Q28bVMnJyYiKisLZs2dhbm6OVq1aYceOHbCwsAAA2NnZAQAcHByUGkrA08aTXC4vt47x48djzpw5eP/99yGVStXm++WXX/Dw4UPMmzcPa9euRUZGBjp37qw4PmbMGBgZGeH3339XxAcAbm5uePfddyE894mtqLydO3dizJgxeO+99xRpPj4+5V4LERERqaeXQ365ubkICwvD0KFDkZ2djfT0dAQHBys1TLQ1adIkFBcXIz4+vtx8CQkJCAsLg7GxMcLCwpCQkKA4duvWLezZswdjx44VNaaeJZGIF44rrzwAkMvl+Pnnn5Gfn1/FKyMiIqJn6W2Dqri4GMHBwXBxcYG3tzfGjBkDS0tLjcsICwuDpaWlaLt8+bIoj7m5OebMmYPo6GjcvXtXZTmFhYVITk7GoEGDAACDBg3Ct99+i3/++QcAcPbsWQiCAE9PT9F5derUUdQ7ffp0jcsDgC+++AL5+fmQy+V47bXXMGrUKOzatUvjayciIs2UCpIa2+jF0ssGlY+PD/z8/ODt7Y333nsPq1atqvT8odjYWBw7dky0OTk5KeUbNmwY7O3t8Z///EdlORs3boS7u7tiyK1ly5ZwdnbG5s2by63/4MGDOHbsGJo3b46ioqJKldesWTOcOHECv/32G4YOHYobN27g7bffxgcffKC2vqKiIhQWFoq2Z+slIiLSZ3rZoDI0NERqaip27dqFZs2aIT4+Hp6enrhw4YLGZcjlcnh4eIg2IyPlKWlGRkZYsGABFi9ejGvXrikdT0hIwMmTJ2FkZKTYTp06hcTERACAh4cHJBIJcnJyROe5ubnBw8NDNFFek/LKGBgYoF27dpg0aRK2bt2K1atXIyEhQe1rEB0dDWtra9G2fPlyjV8vIiJ9JAg1t9GLpZcNKuDpvCNfX19ERUXh6NGjMDExwbZt23RS13vvvYfmzZsjKipKlH78+HH8/vvvSE9PF/V0paenIzMzE3/99Rfs7e3Ro0cPLF26FPfv3y+3Hk3KU6dZs2YAoLaOyMhI3L17V7SNGjWqkq8EERHRq0kvn/LLyspCWloaAgIC4ODggKysLOTn58PLy0vjMgoKCpCXlydKs7KyUjtx/NNPP0VgYKAoLSEhAe3bt0eXLl2U8rdr1w4JCQlYtGgRli1bBl9fX7Rt2xZz587Fa6+9BgMDAxw6dAh//fUX2rRpU6nyQkND4evri86dO0Mul+PChQuIjIxEkyZN0LRpU5XxS6VSpScVb5bz5CIREbGnSJ/oZQ+VTCbD/v378dZbb6FJkyaYNWsWYmJi0LNnT43LiIiIQL169URbeU/zde/eHd27d0dxcTEA4PHjx1i3bh1CQkJU5g8JCcHatWvx5MkTuLu74+jRo/D390dkZCR8fHzQtm1bxMfH48MPP8T8+fMrVV5gYCC+//57vP3222jSpAmGDBmCpk2bYs+ePSqHLYmIiKh8EqG61wogvXH+3LmaDkFjEokErm5uAIAL589X+xIZ1Y3x6l5ti5nxvhhu7u7VWt6G/9bcdb//Op/0e5HYHUFERKQjpbWjHUnVQC+H/IiIiIiqE3uoiIiIdETgApt6gz1URERERFpig4qIiIhISxzyIyIi0pFa8nAjVQP2UBERERFpiT1UREREOsJlE/QHe6iIiIiItMQeKiIiIh3hHCr9wR4qIiIiIi2xQUVERESkJQ75ERER6QiH/PQHe6iIiIiItMQeKiIiIh3hsgn6gz1URERERFpig4qIiIhISxzyIyIi0hFOStcf7KEiIiIi0hJ7qIiIiHSktLSmI6AXhT1UGnBxcYFEIlG7hYeHA4Da45s2bVKUVVJSgtjYWHh7e8PU1BS2trbo2bMnfv31V1Gdq1evVpxvYGCABg0aICIiAjdu3FDkebYOCwsLNG7cGOHh4Th8+LCorPT0dEgkEhQUFIj2VW15eXm6eRGJiIheYeyh0sChQ4dQUlICAMjIyEBISAhycnIgk8kAAGZmZoq8SUlJCAoKEp1vY/N/7d17XBTX/T/+1y663FdEQUACgriEWGq9VEO1VctNTEwsaAKxFvEWqwZRcpFYE0nzDU2VYMJHQ423ppFaIFXRGnU1ISRiiFGxXigXNbVRUIMC8cIK7Pn94YP5Oe6Ci8sCZl/Px2MeDzlzzpn3TMj69j1nZl0AAEIIxMbGYv/+/Vi5ciVCQ0NRX1+PNWvWYNy4ccjNzcXkyZOlcWq1GmVlZdDr9Th+/DgSEhJw8eJF7N271+B4DQ0NKC8vx7p16zBq1Chs3LgRv/vd79o8r7vPoYW7u3u7rw8RERnHNVTWgwnVPfLy8pCamorKyko4ODhg6NCh2LFjBxwdHQEArq6uAO4kHi2J0t1cXFzg4eFhdO6cnBzk5eUhPz8fkyZNktrXrVuHmpoazJ49G+Hh4dKxFAqFNJeXlxcSExOxfPly3Lp1S0ri7j7egAEDEBERgfj4eCxcuBCTJk1C7969Wz3X1s6BiIiI2oe3/O5SVVWFuLg4zJw5E6WlpSgoKEB0dDREB/0TIzs7GxqNRpZMtUhOTkZNTQ20Wm2r4+3t7aHX69HU1NTmcRYvXowffvihzbmIiIio47BCdZeqqio0NTUhOjoavr6+AIDg4OB2zREXFwcbGxtZ2+nTp+Hj44Py8nIEBQUZHdfSXl5ebnR/RUUFsrKyMGLECDg7O7cZw6OPPgoA+Pbbb9vs5+3tLfvZ19cXp06dMtpXp9NBp9MZtNna2rZ5DCIia8ZbftaDCdVdhgwZgtDQUAQHByMyMhIRERGYMmVKm7fN7pWRkYGwsDBZm5eXl/Tn9lS76urq4OTkBL1ej4aGBowZMwbr16+/77iWYygUijb7ffHFF7LkrGfPnq32TUtLQ2pqqqwt8YUXsGjRovvGQ0RE9GPHhOouNjY20Gq1KCoqwr59+5CZmYlly5ahuLgYfn5+Js3h4eGBgIAAo/s0Gg1KS0uN7mtp12g0UpuzszOOHj0KpVIJT09P2eL3trTMdb+Y/fz8TF5DlZKSgiVLlsjaLnz3nUljiYisFb/Lz3pwDdU9FAoFRo8ejdTUVBw7dgwqlQrbtm3rkLljY2NRUVGBnTt3GuxLT09Hnz59EB4eLrUplUoEBATA39/f5GQKAFavXg21Wm1QKTOHra0t1Gq1bOPtPiIiojtYobpLcXExDhw4gIiICLi7u6O4uBhXrlxpdd2TMbW1tQbvcnJ2doajoyNiY2ORm5uL+Ph4g9cm5OfnIzc3V3rCr73H0+l0KC8vx1/+8hds374dH3744X2rT5cvX0ZDQ4OsrU+fPm3e+iMiIiJDTKjuolarUVhYiNWrV6O+vh6+vr5IT09HVFSUyXMkJCQYtKWlpWHp0qVQKBTIycnB6tWrkZGRgfnz58POzg4hISEoKCjA6NGj2x1zy/Hs7OzQv39/jBkzBl9//TWGDRt237GBgYEGbYcOHcLjjz/e7jiIiMhQRz0l/mDaXkdLHUshuva/Nj3Ezp4509UhmEyhUMDP3x8AcO7s2S7+kLs/xmt5D1vMjLdz+A8c2KHz/d/urjvvhROZUHUmVqiIiIgs5CHJI6kDcFE6ERERkZmYUBERERGZibf8iIiILESv7+oIqLOwQkVERERkJlaoiIiILISL0q0HK1RERERksqtXr2LatGlQq9VwcXHBrFmzcP369TbHNDQ0YMGCBejTpw+cnJwQExODS5cuyfooFAqDbevWrbI+BQUFGDZsGGxtbREQEIDNmzd39Ok9MCZUREREFqIXXbdZyrRp03Dq1ClotVrs2rULhYWFmDt3bptjFi9ejJ07dyI3Nxeff/45Ll68iOjoaIN+mzZtQlVVlbRNnjxZ2nfu3Dk88cQTGD9+PEpKSpCUlITZs2dj7969HX2KD4S3/IiIiMgkpaWl2LNnDw4fPowRI0YAADIzMzFx4kSsWrUKXl5eBmPq6uqwYcMGZGdn49e//jWAO4lTUFAQvvrqK9m3c7i4uMDDw8PosbOysuDn54f09HQAQFBQEL788ktkZGQgMjKyo0+13VihIiIi+hHS6XSor6+XbTqdzqw5Dx06BBcXFymZAoCwsDAolUoUFxcbHXPkyBE0NjYiLCxManv00Ufh4+ODQ4cOyfouWLAAffv2xciRI7Fx40bZG/YPHTokmwMAIiMjDeboKkyoiIiILESIrtvS0tLQq1cv2ZaWlmbW+VRXV8Pd3V3W1qNHD7i6uqK6urrVMSqVCi4uLrL2fv36yca88cYbyMnJgVarRUxMDObPn4/MzEzZPP369TOYo76+Hrdu3TLrvDoCb/kRERH9CKWkpGDJkiWyNltbW6N9ly5dirfffrvN+UpLSzssNmOWL18u/Xno0KG4ceMGVq5cicTERIset6MwoSIiIrIQYcnV4fdha2vbagJ1r+TkZMyYMaPNPv7+/vDw8MDly5dl7U1NTbh69Wqra588PDxw+/Zt1NbWyqpUly5danUMAIwaNQp//OMfodPpYGtrCw8PD4MnAy9dugS1Wg17e/u2T7ATMKEiIiKycm5ubnBzc7tvv5CQENTW1uLIkSMYPnw4AODTTz+FXq/HqFGjjI4ZPnw4evbsiQMHDiAmJgYAUFZWhvPnzyMkJKTVY5WUlKB3795SUhgSEoLdu3fL+mi12jbn6ExMqIiIiMgkQUFBmDBhAubMmYOsrCw0NjZi4cKFiI2NlZ7wu3DhAkJDQ/Hhhx9i5MiR6NWrF2bNmoUlS5bA1dUVarUaL7zwAkJCQqQn/Hbu3IlLly7h8ccfh52dHbRaLd566y28+OKL0rHnzZuH//u//8PLL7+MmTNn4tNPP0VOTg7+9a9/dcm1uBcTKiIiIgvpwjt+FrNlyxYsXLgQoaGhUCqViImJwXvvvSftb2xsRFlZGW7evCm1ZWRkSH11Oh0iIyOxdu1aaX/Pnj2xZs0aLF68GEIIBAQE4J133sGcOXOkPn5+fvjXv/6FxYsX491334W3tzfWr1/fLV6ZADChIiIionZwdXVFdnZ2q/sHDBgge90BANjZ2WHNmjVYs2aN0TETJkzAhAkT7nvscePG4dixY+0LuJMwoSIiIrIQfpef9eB7qIiIiIjMxAoVERGRheh/jIuoyChWqEw0YMAAo9+E3bK1vL+jtf13f2N2c3MzMjIyEBwcDDs7O/Tu3RtRUVE4ePCg7JibN2+WxiuVSnh7eyMhIUH2DhBjxxozZoxsnl27dmHs2LFwdnaGg4MDfv7znxt8Q/e3334LhUKBkpKSDr1uRERE1oAVKhMdPnwYzc3NAICioiLExMSgrKwMarUaAGQvFdu0aZPB4rqWl5kJIRAbG4v9+/dj5cqVCA0NRX19PdasWYNx48YhNzdX9u3aarUaZWVl0Ov1OH78OBISEnDx4kXZt2vfezyVSiX9OTMzE0lJSXjllVfw/vvvQ6VSYceOHZg3bx5OnjyJVatWddg1IiIislZMqIzIy8tDamoqKisr4eDggKFDh2LHjh1wdHQEcOcJBwBwd3c3+G4ioO1vy87JyUFeXh7y8/MxadIkqX3dunWoqanB7NmzER4eLh1LoVBIc3l5eSExMRHLly/HrVu3pCSuteP973//Q3JyMpKSkvDWW29J7cnJyVCpVEhMTMTUqVNbfRkbERGZh4vSrQdv+d2jqqoKcXFxmDlzJkpLS1FQUIDo6GiDR0AfVHZ2NjQajSyZapGcnIyamhpotdpWx9vb20Ov16Opqem+x8rLy0NjY6PsxWgtnn/+eTg5OeHvf/97+06AiIiIDLBCdY+qqio0NTUhOjoavr6+AIDg4OB2zREXFwcbGxtZ2+nTp+Hj44Py8nIEBQUZHdfSXl5ebnR/RUUFsrKyMGLECDg7O7d6vI8++giTJ09GeXk5evXqBU9PT4O5VCoV/P39Wz3WvXQ6HXQ6nUGbqd8TRURkjVihsh5MqO4xZMgQhIaGIjg4GJGRkYiIiMCUKVPQu3dvk+fIyMhAWFiYrK3llfwA2lXtqqurg5OTE/R6PRoaGjBmzBisX7++zeMZS6DMlZaWhtTUVFlb4gsvYNGiRR1+LCIioocNE6p72NjYQKvVoqioCPv27UNmZiaWLVuG4uJi+Pn5mTSHh4cHAgICjO7TaDQoLS01uq+lXaPRSG3Ozs44evQolEolPD09jX6jdmvH02g0qKurw8WLF2UJHQDcvn0bZ86cwfjx4006p5SUFCxZskTWduG770waS0RE9GPHNVRGKBQKjB49GqmpqTh27BhUKhW2bdvWIXPHxsaioqICO3fuNNiXnp6OPn36IDw8XGpTKpUICAiAv7+/0WSqLTExMejZsyfS09MN9mVlZeHGjRuIi4szaS5bW1uo1WrZxtt9RERt0wvRZRt1Llao7lFcXIwDBw4gIiIC7u7uKC4uxpUrV1pd92RMbW0tqqurZW3Ozs5wdHREbGwscnNzER8fb/DahPz8fOTm5kpP+JnLx8cHf/7zn5GcnAw7OztMnz4dPXv2xI4dO/Dqq68iOTmZT/gRERF1ACZU91Cr1SgsLMTq1atRX18PX19fpKenIyoqyuQ5EhISDNrS0tKwdOlSKBQK5OTkYPXq1cjIyMD8+fNhZ2eHkJAQFBQUYPTo0R15OkhKSoK/vz9WrVqFd999F83NzRg8eDDef/99o3ESEVHHEfqujoA6i0J01PsAyOqcPXOmq0MwmUKhgJ+/PwDg3NmzHfYaDEthvJb3sMXMeDuH/8CBHTrfG1vu/4obS3ltGmsmnYlXm4iIyEIelkSSzMdF6URERERmYkJFREREZCbe8iMiIrIQPRelWw1WqIiIiIjMxAoVERGRhXBRuvVghYqIiIjITEyoiIiIiMzEW35EREQWoucdP6vBChURERGRmVihIiIishDBEpXVYIWKiIiIyEysUBEREVkI35pgPVihIiIiIjITEyoiIiIiM/GWHxERkYXouSjdarBCRURERGQmVqiIiIgshN/lZz1YoSIiIiIyExOquwwYMAAKhaLVbcaMGQDQ6v6tW7dKczU3NyMjIwPBwcGws7ND7969ERUVhYMHD8qOuXnzZmm8UqmEt7c3EhIScPnyZVm/zz77DE8++STc3NxgZ2eHgQMH4tlnn0VhYaGs3wcffIAhQ4bAyckJLi4uGDp0KNLS0qT9K1asgEKhwLx582TjSkpKoFAo8O2333bAlSQiIrIuvOV3l8OHD6O5uRkAUFRUhJiYGJSVlUGtVgMA7O3tpb6bNm3ChAkTZONdXFwA3CnxxsbGYv/+/Vi5ciVCQ0NRX1+PNWvWYNy4ccjNzcXkyZOlcWq1GmVlZdDr9Th+/DgSEhJw8eJF7N27FwCwdu1aLFy4ENOnT8c//vEPDBw4EHV1dfjss8+wePFiHDlyBACwceNGJCUl4b333sPYsWOh0+nw73//GydPnpTFaWdnhw0bNiA5ORmDBg3q0GtIRET/P6Hv6gios1htQpWXl4fU1FRUVlbCwcEBQ4cOxY4dO+Do6AgAcHV1BQC4u7tLidLdXFxc4OHhYXTunJwc5OXlIT8/H5MmTZLa161bh5qaGsyePRvh4eHSsRQKhTSXl5cXEhMTsXz5cty6dQtXrlxBUlISkpKS8M4778iO89Of/hSJiYnSz/n5+XjmmWcwa9YsqW3w4MEG8QUGBsLd3R3Lli1DTk6OKZeLiIiI2mCVt/yqqqoQFxeHmTNnorS0FAUFBYiOju6wxYPZ2dnQaDSyZKpFcnIyampqoNVqWx1vb28PvV6PpqYmfPzxx2hsbMTLL79stK9CoZD+7OHhga+++gr//e9/7xvjn/70J3z88cf45ptvTDgjIiJ6EHohumyjzmW1CVVTUxOio6MxYMAABAcHY/78+XBycjJ5jri4ODg5Ocm28+fPAwDKy8sRFBRkdFxLe3l5udH9FRUVyMrKwogRI+Ds7Izy8nKo1WpZNezjjz+WHffEiRMAgNdffx0uLi4YMGAAAgMDMWPGDOTk5ECvN6w5Dxs2DM888wxeeeUVk8+ZiIiIjLPKW35DhgxBaGgogoODERkZiYiICEyZMgW9e/c2eY6MjAyEhYXJ2ry8vKQ/t6faVVdXBycnJ+j1ejQ0NGDMmDFYv369tP/uKhQAREZGoqSkBBcuXMC4ceOkdV+enp44dOgQTp48icLCQhQVFSE+Ph7r16/Hnj17oFTK8+c333wTQUFB2LdvH9zd3duMUafTQafTGbTZ2tqafJ5ERNaGr02wHlZZobKxsYFWq8Unn3yCxx57DJmZmQgMDMS5c+dMnsPDwwMBAQGyrUePO/mpRqNBaWmp0XEt7RqNRmpzdnZGSUkJTp48iRs3bqCwsFDaP2jQINTV1aG6ulrq7+TkhICAAPj6+ho9xk9+8hPMnz8fH330EbRaLbRaLT7//HODfgMHDsScOXOwdOnS+/5Pn5aWhl69esm2rKysNscQERFZC6tMqIA7VZ/Ro0cjNTUVx44dg0qlwrZt2zpk7tjYWFRUVGDnzp0G+9LT09GnTx+Eh4dLbUqlEgEBAfD395c9SQgAU6ZMQc+ePfH2228/UCyPPfYYAODGjRtG97/22msoLy+XvfLBmJSUFNTV1cm2e1+9QEREZK2s8pZfcXExDhw4gIiICLi7u6O4uBhXrlxpdd2TMbW1tbKqEXCn0uTo6IjY2Fjk5uYiPj7e4LUJ+fn5yM3NlZ7wux8fHx+kp6dj0aJFuHr1KmbMmAE/Pz9cvXoVH330EYA7FTcA+P3vfw8vLy/8+te/hre3N6qqqvDmm2/Czc0NISEhRufv168flixZgpUrV7YZh62trcHtve95u4+IqE38Lj/rYZUVKrVajcLCQkycOBEajQZ/+MMfkJ6ejqioKJPnSEhIgKenp2zLzMwEcKf6lZOTg1dffRUZGRkIDAzEL3/5S/z3v/9FQUGB7B1UpnjhhRewb98+XLlyBVOmTMGgQYMwceJEnDt3Dnv27EFwcDAAICwsDF999RWmTp0KjUaDmJgY2NnZ4cCBA+jTp0+r87/44ovtWpBPREREcgrBFXP0gM6eOdPVIZhMoVDAz98fAHDu7Nluv1CU8VrewxYz4+0c/gMHduh8SZnXO3S+9lj9Av+h3JmsskJFRERE1JGYUBERERGZySoXpRMREXUGwUXpVoMVKiIiIiIzsUJFRERkIfxOPevBChURERGRmVihIiIishCuobIerFARERERmYkJFREREZGZeMuPiIjIQnjLz3qwQkVERERkJlaoiIiILIQFKuvBChURERGRmZhQEREREZmJt/yIiIgshIvSrQcrVERERERmYoWKiIjIQgS/y89qsEJFREREZCYmVERERERm4i0/IiIiC9FzUbrVYIXKiAEDBkChULS6zZgxAwBa3b9161ZprubmZmRkZCA4OBh2dnbo3bs3oqKicPDgQdkxN2/eLI1XKpXw9vZGQkICLl++LPVRKBTYvn279HNjYyPi4uLQv39/nDx50qSYCgoKZO1ubm6YOHEiTpw4YaGrSURE9OPHCpURhw8fRnNzMwCgqKgIMTExKCsrg1qtBgDY29tLfTdt2oQJEybIxru4uAC4sxgxNjYW+/fvx8qVKxEaGor6+nqsWbMG48aNQ25uLiZPniyNU6vVKCsrg16vx/Hjx5GQkICLFy9i7969BjHevHkTMTExqKiowJdffgk/Pz+TYmrRcj4XL17ESy+9hCeeeAKVlZVQqVTtvl5ERGQcF6VbD6uvUOXl5SE4OBj29vbo06cPwsLC4ODgAA8PD3h4eMDV1RUA4O7uLrX16tVLGu/i4iK1t2x2dnYAgJycHOTl5eHDDz/E7Nmz4efnhyFDhmDdunV46qmnMHv2bNy4cUOaS6FQwMPDA15eXoiKikJiYiL279+PW7duyWKura1FeHg4Ll68aJBM3S+mFi3nM2zYMCQlJeF///sf/vOf/3TotSUioh+fq1evYtq0aVCr1XBxccGsWbNw/fr1Nsc0NDRgwYIF6NOnD5ycnBATE4NLly5J++++S3Pv1nKn5t47LC1bdXW1Rc/XVFadUFVVVSEuLg4zZ85EaWkpCgoKEB0d3WH/osjOzoZGo8GkSZMM9iUnJ6OmpgZarbbV8fb29tDr9WhqapLaqqurMXbsWADA559/Dg8PD7NirKurk24HsjpFRNSxhF502WYp06ZNw6lTp6DVarFr1y4UFhZi7ty5bY5ZvHgxdu7cidzcXHz++ee4ePEioqOjpf3PPvssqqqqZFtkZCTGjh0Ld3d32VxlZWWyfvfu7ypWfcuvqqoKTU1NiI6Ohq+vLwAgODi4XXPExcXBxsZG1nb69Gn4+PigvLwcQUFBRse1tJeXlxvdX1FRgaysLIwYMQLOzs5S+6JFi+Dv7w+tVgsHB4d2x9TC29sbAKQK2VNPPYVHH320rVMlIiIrV1paij179uDw4cMYMWIEACAzMxMTJ07EqlWr4OXlZTCmrq4OGzZsQHZ2Nn79618DuLM0JSgoCF999RUef/xx2Nvby5bTXLlyBZ9++ik2bNhgMJ+7u7vBMpbuwKorVEOGDEFoaCiCg4MxdepUfPDBB7h27Vq75sjIyEBJSYlsu/sXqj3Vrrq6Ojg5OcHBwQGBgYHo168ftmzZIuvz5JNPory8HH/5y18eOCYA+OKLL3DkyBFs3rwZGo0GWVlZbcam0+lQX18v23Q6ncnnRkREncsSn9uHDh2Ci4uLlEwBQFhYGJRKJYqLi42OOXLkCBobGxEWFia1Pfroo/Dx8cGhQ4eMjvnwww/h4OCAKVOmGOz72c9+Bk9PT4SHhxs84NWVrDqhsrGxgVarxSeffILHHnsMmZmZCAwMxLlz50yew8PDAwEBAbKtR487hT+NRoPS0lKj41raNRqN1Obs7IySkhKcPHkSN27cQGFhoWw/AEyfPh0bN27Eiy++iHfeeafdMbXw8/NDYGAg4uPjMXv2bDz77LNtnmdaWhp69eol2+6XhBERWbuuvOVn7HM7LS3NrPOprq42uMXWo0cPuLq6trqWqbq6GiqVyqCq1K9fv1bHbNiwAc8995ysauXp6YmsrCx8/PHH+Pjjj/HII49g3LhxOHr0qFnn1FGsOqEC7iwEHz16NFJTU3Hs2DGoVCps27atQ+aOjY1FRUUFdu7cabAvPT0dffr0QXh4uNSmVCoREBAAf39/2S/RveLj47F582a8/PLLWLVqldlxLliwACdPnmzzvFNSUlBXVyfb5s2bZ/axiYjIMox9bqekpBjtu3Tp0jZfF6RQKDrtwaVDhw6htLQUs2bNkrUHBgbi+eefx/Dhw/GLX/wCGzduxC9+8QtkZGR0Slz3Y9VrqIqLi3HgwAFERETA3d0dxcXFuHLlSqvrnoypra01yLCdnZ3h6OiI2NhY5ObmIj4+3uC1Cfn5+cjNzYWjo+MDxT59+nQolUrEx8dDCIGXXnrJpJiMcXBwwJw5c/D6669j8uTJUCgUBn1sbW1ha2sra/v+np+JiEhO34WvTTD2ud2a5ORk6R2LrfH394eHh4fs/YgA0NTUhKtXr7b6kJSHhwdu376N2tpaWZXq0qVLRsesX78eP/vZzzB8+PD7xj1y5Eh8+eWX9+3XGaw6oVKr1SgsLMTq1atRX18PX19fpKenIyoqyuQ5EhISDNrS0tKkbD8nJwerV69GRkYG5s+fDzs7O4SEhKCgoACjR482K/5p06ZBqVRi+vTp0Ov1eOWVV+4bU2sWLlyId955B7m5uXjmmWfMiouIiB4ubm5ucHNzu2+/kJAQ1NbW4siRI1LC8+mnn0Kv12PUqFFGxwwfPhw9e/bEgQMHEBMTA+DOk3rnz59HSEiIrO/169eRk5Nj8q3JkpISeHp6mtTX0hSCbx2jB3T2zJmuDsFkCoUCfv7+AIBzZ892+5ftMV7Le9hiZrydw3/gwA6db8aKS/fvZCGbV/SzyLxRUVG4dOkSsrKy0NjYiISEBIwYMQLZ2dkAgAsXLiA0NBQffvghRo4cCQD4/e9/j927d2Pz5s1Qq9V44YUXANx5efbdNmzYgIULF6KqqspgzdXq1avh5+eHwYMHo6GhAevXr0dmZib27duH0NBQi5xre1h1hYqIiMiSLPk+qK6yZcsWLFy4EKGhoVAqlYiJicF7770n7W9sbERZWRlu3rwptWVkZEh9dTodIiMjsXbtWoO5N2zYgOjoaKOvRbh9+zaSk5Nx4cIFODg44Kc//Sn279+P8ePHW+Q824sVKnpgrFBZDuO1vIctZsbbOTq6QhX/Wte9xfuvb5j34mdqH1aoiIiILORhSSTJfFb/2gQiIiIic7FCRUREZCH6H+EaKjKOFSoiIiIiMzGhIiIiIjITb/kRERFZyI/xtQlkHCtURERERGZihYqIiMhC+NoE68EKFREREZGZmFARERERmYm3/IiIiCxE6PVdHQJ1ElaoiIiIiMzEChUREZGF8E3p1oMVKiIiIiIzsUJFRERkIXxtgvVghYqIiIjITEyoiIiIiMzEW35EREQWwu/ysx6sULViwIABUCgUrW4zZswAgFb3b926VZqrubkZGRkZCA4Ohp2dHXr37o2oqCgcPHhQdszNmzdL45VKJby9vZGQkIDLly9LfRQKBbZv32405oKCAlkM/fr1Q0xMDM6ePSvrd+zYMTz77LPw9PSEra0tfH198eSTT2Lnzp28309ERPQAWKFqxeHDh9Hc3AwAKCoqQkxMDMrKyqBWqwEA9vb2Ut9NmzZhwoQJsvEuLi4A7ixIjI2Nxf79+7Fy5UqEhoaivr4ea9aswbhx45Cbm4vJkydL49RqNcrKyqDX63H8+HEkJCTg4sWL2Lt3r8mxl5WVwdnZGRUVFZg7dy4mTZqEf//737CxscGOHTvwzDPPICwsDH/9618REBAAnU6HoqIi/OEPf8Avf/lLKXYiIjIPK1TWgwkVgLy8PKSmpqKyshIODg4YOnQoduzYAUdHRwCAq6srAMDd3d1osuHi4gIPDw+jc+fk5CAvLw/5+fmYNGmS1L5u3TrU1NRg9uzZCA8Pl46lUCikuby8vJCYmIjly5fj1q1bsiSuLS1xenp64rXXXsO0adNQWVkJb29vzJo1C0888QT++c9/ysYEBQVh1qxZrFARERE9AKu/5VdVVYW4uDjMnDkTpaWlKCgoQHR0dIclFtnZ2dBoNLJkqkVycjJqamqg1WpbHW9vbw+9Xo+mpqYHOn5LEnb79m3s27cPNTU1ePnll1vtr1AoHug4RERE1szqK1RVVVVoampCdHQ0fH19AQDBwcHtmiMuLg42NjayttOnT8PHxwfl5eUICgoyOq6lvby83Oj+iooKZGVlYcSIEXB2dm5XTMCdc1u1ahX69++PwMBA7N69GwAQGBgo9Tl8+DDGjx8v/bx161Y8+eST7T4WEREZ0gt+l5+1sPqEasiQIQgNDUVwcDAiIyMRERGBKVOmoHfv3ibPkZGRgbCwMFmbl5eX9Of2VLvq6urg5OQEvV6PhoYGjBkzBuvXrzd5PAB4e3tDCIGbN29iyJAh+Pjjj6FSqYz2/elPf4qSkhIAwKBBg1qthOl0Ouh0OoM2W1vbdsVGRET0Y2T1CZWNjQ20Wi2Kioqwb98+ZGZmYtmyZSguLoafn59Jc3h4eCAgIMDoPo1Gg9LSUqP7Wto1Go3U5uzsjKNHj0KpVMLT09PkdVN3++KLL6BWq+Hu7i6rbA0aNAjAnUXrjz/+OADA1ta21djvlpaWhtTUVFlb4gsvYNGiRe2Oj4jIWnBRuvWw+jVUwJ11Q6NHj0ZqaiqOHTsGlUqFbdu2dcjcsbGxqKiowM6dOw32paeno0+fPggPD5falEolAgIC4O/v/0DJFAD4+flh4MCBBrcJIyIi4Orqirfffrvdc6akpKCurk62zZs374HiIyIi+rGx+gpVcXExDhw4gIiICLi7u6O4uBhXrlxpdd2TMbW1taiurpa1OTs7w9HREbGxscjNzUV8fLzBaxPy8/ORm5srPeFnqnPnzkm36Vq0VJ/a4uTkhPXr1+PZZ5/FE088gcTERAwaNAjXr1/Hnj17AMBgLVgLW1tbg9t73/N2HxFRm1ihsh5Wn1Cp1WoUFhZi9erVqK+vh6+vL9LT0xEVFWXyHAkJCQZtaWlpWLp0KRQKBXJycrB69WpkZGRg/vz5sLOzQ0hICAoKCjB69Oh2x7xkyRKDti+++MKksb/5zW9QVFSEt99+G7/73e9w9epV9OrVCyNGjOCCdCIiogekEHzxED2gs2fOdHUIJlMoFPDz9wcAnDt7ttu/b4vxWt7DFjPj7Rz+Awd26HyT5xt/irszbF+ruX8n6jBWX6EiIiKylIclkSTzcVE6ERERkZlYoSIiIrIQvZ4v9rQWrFARERERmYkJFREREZGZeMuPiIjIQvgeKuvBChURERGRmVihIiIishAhuCjdWrBCRURERGQmVqiIiIgshGuorAcrVERERERmYkJFREREZCbe8iMiIrIQ3vKzHqxQEREREZmJFSoiIiIL0fO1CVaDFSoiIiIiMzGhIiIiIjITb/kRERFZCBelWw9WqIiIiIjMxAoVERGRhQg9F6VbC1ao7jJgwAAoFIpWtxkzZgBAq/u3bt0qzdXc3IyMjAwEBwfDzs4OvXv3RlRUFA4ePCg75ubNm6XxSqUS3t7eSEhIwOXLl2X9du3ahbFjx8LZ2RkODg74+c9/js2bN0v7V6xY0WbsCoUCADBjxgxMnjzZ4NwLCgqgUChQW1vbIdeSiIjImrBCdZfDhw+jubkZAFBUVISYmBiUlZVBrVYDAOzt7aW+mzZtwoQJE2TjXVxcAABCCMTGxmL//v1YuXIlQkNDUV9fjzVr1mDcuHHIzc2VJTVqtRplZWXQ6/U4fvw4EhIScPHiRezduxcAkJmZiaSkJLzyyit4//33oVKpsGPHDsybNw8nT57EqlWr8OKLL2LevHnSnD//+c8xd+5czJkzxxKXioiITMA1VNbDahOqvLw8pKamorKyEg4ODhg6dCh27NgBR0dHAICrqysAwN3dXUqU7ubi4gIPDw+jc+fk5CAvLw/5+fmYNGmS1L5u3TrU1NRg9uzZCA8Pl46lUCikuby8vJCYmIjly5fj1q1b+P7775GcnIykpCS89dZb0lzJyclQqVRITEzE1KlTMWrUKDg5OUn7bWxs4Ozs3GqMRERE1HGs8pZfVVUV4uLiMHPmTJSWlqKgoADR0dEQomP+JZGdnQ2NRiNLplokJyejpqYGWq221fH29vbQ6/VoampCXl4eGhsb8eKLLxr0e/755+Hk5IS///3vHRI3ERERPRirrFBVVVWhqakJ0dHR8PX1BQAEBwe3a464uDjY2NjI2k6fPg0fHx+Ul5cjKCjI6LiW9vLycqP7KyoqkJWVhREjRsDZ2Rnl5eXo1asXPD09DfqqVCr4+/u3Oldrdu3aJatmAZBudbZGp9NBp9MZtNna2rbr2ERE1kTwTelWwyorVEOGDEFoaCiCg4MxdepUfPDBB7h27Vq75sjIyEBJSYls8/Lykva3p9pVV1cHJycnODg4IDAwEP369cOWLVvaFU97jB8/3iD29evXtzkmLS0NvXr1km1ZWVkWi5GIiOhhYpUVKhsbG2i1WhQVFWHfvn3IzMzEsmXLUFxcDD8/P5Pm8PDwQEBAgNF9Go0GpaWlRve1tGs0GqnN2dkZR48ehVKphKenp2zxu0ajQV1dHS5evChL2ADg9u3bOHPmDMaPH29SzC0cHR0NYv/uu+/aHJOSkoIlS5bI2i7cZwwRkbXTc1G61bDKChVwZyH46NGjkZqaimPHjkGlUmHbtm0dMndsbCwqKiqwc+dOg33p6eno06cPwsPDpTalUomAgAD4+/vLkikAiImJQc+ePZGenm4wV1ZWFm7cuIG4uLgOibsttra2UKvVso23+4iIiO6wygpVcXExDhw4gIiICLi7u6O4uBhXrlxpdd2TMbW1taiurpa1OTs7w9HREbGxscjNzUV8fLzBaxPy8/ORm5srPeF3Pz4+Pvjzn/+M5ORk2NnZYfr06ejZsyd27NiBV199FcnJyRg1alS7zp+IiIg6llUmVGq1GoWFhVi9ejXq6+vh6+uL9PR0REVFmTxHQkKCQVtaWhqWLl0KhUKBnJwcrF69GhkZGZg/fz7s7OwQEhKCgoICjB49ul3xJiUlwd/fH6tWrcK7776L5uZmDB48GO+//77ROIiIqHvgm9Kth0J01LsCyOqcPXOmq0MwmUKhgJ+/PwDg3NmzHfaKDEthvJb3sMXMeDuH/8CBHTrfuCmHOnS+9ijIC+myY1sjq6xQERERdQa+Kd16WO2idCIiIqKOwoSKiIiIyEy85UdERGQhfFO69WCFioiIiMhMrFARERFZCBelWw9WqIiIiMhkV69exbRp06BWq+Hi4oJZs2bh+vXrbY5Zt24dxo0bB7VaDYVCgdra2gea99///jd++ctfws7ODo888gj+/Oc/d+SpmYUJFRERkYUIvb7LNkuZNm0aTp06Ba1Wi127dqGwsBBz585tc8zNmzcxYcIEvPrqqw88b319PSIiIuDr64sjR45g5cqVWLFiBdatW9dh52YO3vIjIiIik5SWlmLPnj04fPgwRowYAQDIzMzExIkTsWrVKnh5eRkdl5SUBAAoKCh44Hm3bNmC27dvY+PGjVCpVBg8eDBKSkrwzjvv3Deh6wysUBEREf0I6XQ61NfXyzadTmfWnIcOHYKLi4uU9ABAWFgYlEoliouLLTrvoUOH8Ktf/QoqlUrqExkZibKyMly7du2Bj91RWKGiB9bRX9HQQqfTIS0tDSkpKbC1te3w+Vu+DqOjMF65hy1e4OGLmfFa/neio3y5c2yXHXvFihVITU2Vtb3++utYsWLFA89ZXV0Nd3d3WVuPHj3g6uqK6upqi85bXV0NPz8/WZ9+/fpJ+3r37v3Ax+8IrFBRt6PT6ZCammr2v6Q6C+O1rIctXuDhi5nx/jilpKSgrq5OtqWkpBjtu3TpUigUija3//znP518Bg8XVqiIiIh+hGxtbU2u4CUnJ2PGjBlt9vH394eHhwcuX74sa29qasLVq1fh4eHxoKGaNK+HhwcuXbok69PysznH7ihMqIiIiKycm5sb3Nzc7tsvJCQEtbW1OHLkCIYPHw4A+PTTT6HX6zFq1KgHPr4p84aEhGDZsmVobGxEz549AQBarRaBgYFdfrsP4C0/IiIiMlFQUBAmTJiAOXPm4Ouvv8bBgwexcOFCxMbGSk/4XbhwAY8++ii+/vpraVx1dTVKSkpQWVkJADhx4gRKSkpw9epVk+d97rnnoFKpMGvWLJw6dQr/+Mc/8O6772LJkiWdfBVaIYi6mYaGBvH666+LhoaGrg7FJIzXsh62eIV4+GJmvNQeNTU1Ii4uTjg5OQm1Wi0SEhLEDz/8IO0/d+6cACA+++wzqe31118XAAy2TZs2mTyvEEIcP35cjBkzRtja2or+/fuLP/3pT5Y+XZMphBB8Lz4RERGRGXjLj4iIiMhMTKiIiIiIzMSEioiIiMhMTKiIiIiIzMSEiizqn//8J8LDw+Hm5ga1Wo2QkBDs3bvXoN+aNWswYMAA2NnZYdSoUbLHba9evYoXXngBgYGBsLe3h4+PDxITE1FXVyeb4/z583jiiSfg4OAAd3d3vPTSS2hqaurWMRt7G/HWrVs7PV4AeP755zFw4EDY29vDzc0NTz/9tMGbkTviGndmvB1xfTsy5hZCCERFRUGhUGD79u2yfd3pGpsSb3f6HR43bpxBLPPmzZP16ajPCSIDXfuQIf3YLVq0SLz99tvi66+/FuXl5SIlJUX07NlTHD16VOqzdetWoVKpxMaNG8WpU6fEnDlzhIuLi7h06ZIQQogTJ06I6OhokZ+fLyorK8WBAwfEoEGDRExMjDRHU1OT+MlPfiLCwsLEsWPHxO7du0Xfvn1FSkpKt41ZCCE9NlxVVSVtt27d6vR4hRDiL3/5i/j888/FuXPnxJEjR8SkSZPEI488Ipqamjr0GndWvB11fTsy5hbvvPOOiIqKEgDEtm3bpPbudo3vF68Q3et3eOzYsWLOnDmyWOrq6qT9Hfk5QXQvJlRklr/+9a/C1dXV4H0wTz/9tPjtb39rdMxjjz0mUlNTpZ9HjhwpFixYIP3c3NwsvLy8RFpaWqvHzcnJESqVSjQ2NgohhNi9e7dQKpWiurpa6vP+++8LtVotdDpdt4xZCGH0L6h7dVW8x48fFwBEZWWlEML0a9xd4hXCtOvb2TEfO3ZM9O/fX1RVVRnE1x2vcVvxCtG9fofHjh0rFi1a1Goc7fmcIGov3vIjs0ydOhXNzc3Iz8+X2i5fvox//etfmDlzpkF/vV6PH374Aa6urgCA27dv48iRIwgLC5P6KJVKhIWF4dChQ60et66uDmq1Gj163Pn2pEOHDiE4OFj65nEAiIyMRH19PU6dOtUtY26xYMEC9O3bFyNHjsTGjRsh7nk1XFfEe+PGDWzatAl+fn545JFHAJh+jbtLvC3ud307M+abN2/iueeew5o1a4x+91h3u8b3i7dFd/od3rJlC/r27Yuf/OQnSElJwc2bN6V97fmcIGovJlRkFnt7ezz33HPYtGmT1PbRRx/Bx8cH48aNM+i/atUqXL9+Hc888wwA4Pvvv0dzc7PsAw4A+vXrh+rqaqPH/P777/HHP/4Rc+fOldqqq6uNztGyrzvGDABvvPEGcnJyoNVqERMTg/nz5yMzM7PL4l27di2cnJzg5OSETz75BFqtFiqVCoDp17i7xAuYdn07M+bFixfjF7/4BZ5++mmDOYHud43vFy/QvX6Hn3vuOXz00Uf47LPPkJKSgr/97W/47W9/K+1vz+cEUbt1cYWMfgSOHj0qbGxsxHfffSeEECI4OFi88cYbBv22bNkiHBwchFarldouXLggAIiioiJZ35deekmMHDnSYI66ujoxcuRIMWHCBHH79m2pfc6cOSIiIkLW98aNGwKA2L17d7eM2Zjly5cLb2/vLou3trZWlJeXi88//1xMmjRJDBs2TFoP055r3B3iNaa169sZMe/YsUMEBATIvkoD99wu607X2JR4jenq3+G7HThwQHYbuL2fE0TtwYSKOsSwYcPEW2+9Jb755huhVCrF+fPnZfv//ve/C3t7e7Fr1y5Zu06nEzY2NgYf0r/73e/EU089JWurr68XISEhIjQ01OAvzeXLl4shQ4bI2s6ePSsAyBa2dqeYjdm1a5cAYPQ7yjoj3nvHOTg4iOzsbCFE+69xV8drTFvX19IxL1q0SCgUCmFjYyNtAIRSqRRjx44VQnSva2xKvMZ0p9/h69evCwBiz549QogH+5wgMhUTKuoQa9euFRqNRixYsMDgX4DZ2dnCzs5ObN++3ejYkSNHioULF0o/Nzc3i/79+8sWm9bV1YnHH39cjB07Vty4ccNgjpbFpvc+BaZWq1v9y7OrYzbmzTffFL179+6SeO/V0NAg7O3tpS8vbe817up4jWnr+lo65qqqKnHixAnZBkC8++674uzZs0KI7nWNTYnXmO70O/zll18KAOL48eNCiAf7nCAyFRMq6hC1tbXCwcFBqFQqsXXrVql9y5YtokePHmLNmjWyR5lra2ulPlu3bhW2trZi8+bN4vTp02Lu3LnCxcVFehKnrq5OjBo1SgQHB4vKykrZPPc+0h8RESFKSkrEnj17hJubW5uPQ3d1zPn5+eKDDz4QJ06cEBUVFWLt2rXCwcFBvPbaa50e75kzZ6TKwX//+19x8OBBMWnSJOHq6ir95dPea9zV8bb3+lo6ZmPuvYXWna6xKfF2p9/hyspK8cYbb4hvvvlGnDt3TuzYsUP4+/uLX/3qVw98fYnagwkVdZjp06cbPBo9duxYAcBgi4+Pl43NzMwUPj4+QqVSiZEjR4qvvvpK2vfZZ58ZnQOAOHfunNTv22+/FVFRUcLe3l707dtXJCcny15R0N1i/uSTT8TPfvYz4eTkJBwdHcWQIUNEVlaWaG5u7vR4L1y4IKKiooS7u7vo2bOn8Pb2Fs8995z4z3/+I5ujvde4K+N9kOtryZiNMbYmqbtcY1Pi7U6/w+fPnxe/+tWvhKurq7C1tRUBAQHipZdekr2HSogH+5wgMoVCCCPPEBM9gNDQUAwePBjvvfdeV4disoctZsZreQ9bzIyXqHtgQkVmu3btGgoKCjBlyhScPn0agYGBXR3SfT1sMTNey3vYYma8RN1Lj/t3IWrb0KFDce3aNbz99tsPzYfkwxYz47W8hy1mxkvUvbBCRURERGQmvimdiIiIyExMqIiIiIjMxISKiIiIyExMqIiIiIjMxISKiIiIyExMqIioS8yaNQvBwcG4ffu2rH337t1QqVQ4evRoF0VGRNR+TKiIqEtkZGTghx9+wOuvvy611dbWYs6cOVi+fDmGDRvW4cdsbGzs8DmJiAAmVETUCfLy8hAcHAx7e3v06dMHYWFhsLGxwaZNm5Ceno7i4mIAQFJSEvr374+UlBT873//wzPPPAMXFxe4urri6aefxrfffivNefjwYYSHh6Nv377o1asXxo4da1DVUigUeP/99/HUU0/B0dER/+///b/OPG0isiJMqIjIoqqqqhAXF4eZM2eitLQUBQUFiI6OhhAC48ePx/z58xEfH4/c3Fzk5OTgww8/hBACkZGRcHZ2xhdffIGDBw/CyckJEyZMkG4R/vDDD4iPj8eXX36Jr776CoMGDcLEiRPxww8/yI6/YsUK/OY3v8GJEycwc+bMrrgERGQF+KZ0IrKoo0ePYvjw4fj222/h6+trsP/WrVsYOnQoKioqkJ6ejqSkJHz00Ud48803UVpaCoVCAQC4ffs2XFxcsH37dkRERBjMo9fr4eLiguzsbDz55JMA7lSokpKSkJGRYdmTJCKrxwoVEVnUkCFDEBoaiuDgYEydOhUffPABrl27Ju23t7fHiy++CAcHByxatAgAcPz4cVRWVsLZ2RlOTk5wcnKCq6srGhoacObMGQDApUuXMGfOHAwaNAi9evWCWq3G9evXcf78ednxR4wY0XknS0RWi1+OTEQWZWNjA61Wi6KiIuzbtw+ZmZlYtmwZiouL4efnBwDo0aMHbGxspGrU9evXMXz4cGzZssVgPjc3NwBAfHw8ampq8O6778LX1xe2trYICQkxeGrQ0dHRwmdIRMQKFRF1AoVCgdGjRyM1NRXHjh2DSqXCtm3bWu0/bNgwVFRUwN3dHQEBAbKtV69eAICDBw8iMTEREydOxODBg2Fra4vvv/++s06JiEiGCRURWVRxcTHeeustfPPNNzh//jz++c9/4sqVKwgKCmp1zLRp09C3b188/fTT+OKLL3Du3DkUFBQgMTER3333HQBg0KBB+Nvf/obS0lIUFxdj2rRpsLe376zTIiKSYUJFRBalVqtRWFiIiRMnQqPR4A9/+APS09MRFRXV6hgHBwcUFhbCx8cH0dHRCAoKwqxZs9DQ0AC1Wg0A2LBhA65du4Zhw4Zh+vTpSExMhLu7e2edFhGRDJ/yIyIiIjITK1REREREZmJCRURERGQmJlREREREZmJCRURERGQmJlREREREZmJCRURERGQmJlREREREZmJCRURERGQmJlREREREZmJCRURERGQmJlREREREZmJCRURERGSm/w9DIeMyJyxxuQAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\n", + "# Make a single heatmap that includes all the years\n", + "# Create a df that contains the emissions of each ST for each year\n", + "# The rows are the sST and the columns are sES\n", + "# Each intersection should be divided in 7 columns, one for each year\n", + "# The value of each intersection should be the emissions of the ST for that year\n", + "# The heatmap should have a color scale that goes from 0 to the maximum value of the emissions\n", + "\n", + "# Create a df that contains the emissions of each ST for each year in the transport sector\n", + "\n", + "emissions_2020 = vEmiCO2TE_HEATMAP_2020.pivot(index='sTE', columns='sYear', values='vEmiCO2TE')\n", + "emissions_2025 = vEmiCO2TE_HEATMAP_2025.pivot(index='sTE', columns='sYear', values='vEmiCO2TE')\n", + "emissions_2030 = vEmiCO2TE_HEATMAP_2030.pivot(index='sTE', columns='sYear', values='vEmiCO2TE')\n", + "emissions_2035 = vEmiCO2TE_HEATMAP_2035.pivot(index='sTE', columns='sYear', values='vEmiCO2TE')\n", + "emissions_2040 = vEmiCO2TE_HEATMAP_2040.pivot(index='sTE', columns='sYear', values='vEmiCO2TE')\n", + "emissions_2045 = vEmiCO2TE_HEATMAP_2045.pivot(index='sTE', columns='sYear', values='vEmiCO2TE')\n", + "emissions_2050 = vEmiCO2TE_HEATMAP_2050.pivot(index='sTE', columns='sYear', values='vEmiCO2TE')\n", + "\n", + "# Create a df that contains the emissions of each ST for each year\n", + "emissions = pd.concat([emissions_2020, emissions_2025, emissions_2030, emissions_2035, emissions_2040, emissions_2045, emissions_2050], axis=1)\n", + "\n", + "# replace NaN values with 0\n", + "emissions.fillna(0, inplace=True)\n", + "\n", + "# Increase the size of the plot in sucha way that all the years are visible an sST and sES are readable\n", + "plt.figure(figsize=(5, 8))\n", + "# Create a heatmap\n", + "sns.heatmap(emissions, cmap='coolwarm',vmin=0, vmax=emissions.max().max())\n", + "#Insert a separator between the years\n", + "plt.axvline(x=[1], color='white')\n", + "plt.axvline(x=[2], color='white')\n", + "plt.axvline(x=[3], color='white')\n", + "plt.axvline(x=[4], color='white')\n", + "plt.axvline(x=[5], color='white')\n", + "plt.axvline(x=[6], color='white')\n", + "\n", + "plt.title('CO2 emissions of each TE (Transport + Losses) for each year [ktCO2]', y=1.05)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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FBSEY8eOYc6cOejVqxeysrJgYWGBdu3aYebMmWLcwoUL0bhxYyxduhSTJk2CpqYmmjVrhqSkJHTu3FmMk0gk2LRpExYuXIiYmBgMGzYMOjo6aN26NVJTU+Hm5lZsG7W1tZGYmIiwsDBxAqlRo0Yl9ktJfSAfC6mpqUrbEg4YMAArV64EAEyZMkVpfA4ePBj/+9//Sry3KitWrMCKFSsUyvz9/bFnz55y10VERERERERERET0IeA7j9RDIgiCoO4kiOj917bzL+pOgeiN6Eg1kJzoDgDwCTmM53lFpVxB9P7hOKYPHccwfeg4hulDxzFMHzqOYfqvOPKTp7pT+CCdattKbfd2PXJcbfdWt/fynUdERERERERERERERESkHlVq8igwMBAymUzlMXv2bHWn99Zmz55dbPsCAwPVnd57xcnJqdi+Wrt2rbrTIyIiIiIiIiIiIiIAEk2J2o6q7L1751FlWrlyJZ49e6bynImJyTvOpuINGTIEYWFhKs/p6uq+42zeb7t370ZBQYHKc7Vq1XrH2RARERERERERERERvT+q1ORR3bp11Z1CpTIxMflPTIK9C1ZWVupOgYiIiIiIiIiIiIhKIdGoUhuovTfY60RERERERERERERERCTi5BERERERERERERERERGJqtS2dURERERERERERERE9OGQaEjUnUKVxJVHREREREREREREREREJOLKIyIiIiIiIiIiIiIiei9paHLlkTpw5RERERERERERERERERGJOHlUTrm5uYiKioKNjQ10dHRgamoKT09PbN++HRkZGZBIJCUe8fHxJdafmpoqxmpoaMDIyAguLi4YP348MjMzy5zLqy5cuICwsDCYmppCKpXCzs4OU6ZMQW5urtI9iztSU1MRHx8PY2NjlXlLJBIkJSWVqQ9frdfQ0BCurq5KOcfHx6vMQ0dHR4y5d+8ehg4dCktLS0ilUpibm8Pf3x9Hjx5VqOvs2bMIDQ1FrVq1oKOjgwYNGmDQoEFIT09XiEtISICrqyv09PRgYGAAT09P7Ny5Uyn/Fy9eICYmBs7OztDR0UH16tURGBiodF9V/XXp0iVYWFggNDQU+fn5JfZTSf0NABEREWK/aGtrw9bWFtOnT0dhYaEYIwgCVqxYgdatW8PQ0BAymQxOTk4YOXIkrl27VuL9iYiIiIiIiIiIiNRNoiFR21GVcfKo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ToHojehINZCc6A4A8Ak5jOd5RaVcQfT+4TimDx3HMH3oOIbpQ8cxTB86jmH6rzjyk6e6U/ggXezWXm33dtx2QG33Vje+84iIiIiIiIiIiIiIiIhEnDx6xwIDAyGTyVQes2fPVnd6b2327NnFti8wMFDd6b1XnJyciu2rtWvXqjs9IiIiIiIiIiIiIqqi+M6jd2zlypV49uyZynMmJibvOJuKN2TIEISFhak8p6ur+46zeb/t3r0bBQUFKs/VqlXrHWdDRERERERERERE9P6RaHANjDpw8ugdq1u3rrpTqFQmJib/iUmwd8HKykrdKRARERERERERERERKeHkERERERERERERERERvZckGhJ1p1AlcfKIiMrEunGDN7424/zVCsyE6M3pVTeCZn5Rua97+vBJJWRDRERERPTude7bFoUvyn/dtlWHKj4ZIiIiem9x8oiIiIiIiIiIiIiIiN5LXHmkHnzTFBEREREREREREREREYk4eUREREREREREREREREQibltHRERERERERERERETvJW5bpx5VfuVRbm4uoqKiYGNjAx0dHZiamsLT0xPbt29HRkYGJBJJiUd8fHyJ9aempoqxGhoaMDIygouLC8aPH4/MzMwy5/KqCxcuICwsDKamppBKpbCzs8OUKVOQm5urdM/ijtTUVMTHx8PY2Fhl3hKJBElJSWXqw1frNTQ0hKurq1LO8fHxKvPQ0dERY+7du4ehQ4fC0tISUqkU5ubm8Pf3x9GjRxXqOnv2LEJDQ1GrVi3o6OigQYMGGDRoENLT0xXiEhIS4OrqCj09PRgYGMDT0xM7d+5Uyv/FixeIiYmBs7MzdHR0UL16dQQGBirdV1V/Xbp0CRYWFggNDUV+fn6J/STvg4CAAIXyx48fi5/Jq1JSUtCpUyeYmppCR0cHNjY26NGjBw4dUv2SUnt7e0ilUty5c0fp3M2bN9GrVy/UqVMHOjo6+OijjxAUFITLly+XmDMRERERERERERERVT1VfvJoyJAh2Lp1KxYvXozLly9jz549CAkJwYMHD2BhYYHMzEzxGDt2LJycnBTKevToUab7XLlyBbdv38apU6cQGRmJ5ORkNGrUCL///nuZcpE7fvw4WrZsifz8fOzatQvp6emYNWsW4uPj4evri/z8fLRp00Yhx7CwMAQEBCiUtWnTpkL7MS4uDpmZmTh9+jTc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fx4ZGRlYtWoVIiIiEBISovT+qFdFRUXh9u3bSE5OVjonk8nQo0cPREVFITMzExEREaXmTERERERERERERKRuEg2J2o6qrEpNHhkaGuLQoUPo0KED7OzsMGnSJMyfPx+BgYHw9/dHQkIC/Pz84ODggM8//xz+/v7YtGlThebQsGFD1KlTB82bN8fXX38NHx8f/PHHH3B0dBRjypJLmzZtcPz4cWhqaiIwMBC2traIiopC3759sX//fkil0grN+00FBASgXr16CquPsrKyULt2baXj7t27kMlkaNmyJWJiYuDh4YFGjRph8uTJGDRoEL777juFuqdMmYLatWvD1tYWn3zyCZ48eYIDBw4gMjKy1Ly8vb2RnZ0tvu9IztPTE9nZ2eLk0ZkzZ3Du3DkEBwcr1WFkZIT27dtj1apVpd6vfv36+O233+Dt7Y2xY8eiUaNG8PX1xYEDBxQmDkNCQpCSkoJbt27B3d0dDRs2RExMDCZOnIgNGzaUuFrIxMQEkZGRxa6UGzBgAB49egR/f3/UqVOn1JyJiIiIiIiIiIiIqGqSCIIgqDsJInr/te38i7pTIHojOlINJCe6AwB8Qg7jeV5RKVcQvX84julDxzFMHzqOYfrQcQzTh45jmP4rjvxU/DvIqXh3xvVR273N561R273VrUqtPCIiIiIiIiIiIiIiIqKScfKoggQGBkImk6k8Zs+ere703trs2bOLbV9gYKC601OrW7duFds3MpkMt27dUneKRERERERERERERERlpqXuBP4rVq5ciWfPnqk8Z2Ji8o6zqXhDhgxBWFiYynO6urrvOJv3S506dZCWllbieSIiIiIiIiIiIiIqP4lG8e+Bp8rDyaMKUrduXXWnUKlMTEz+E5NglUFLSwu2trbqToOIiIiIiIiIiIiIqEJw8oiIiIiIiIiIiIiIiN5LXHmkHnznEREREREREREREREREYk4eUREREREREREREREREQibltHRERERERERERERETvJw2ugVEH9joRERERERERERERERGJuPKIiIiIiIiIiIiIiIjeSxKJRN0pVElceVSC3NxcREVFwcbGBjo6OjA1NYWnpye2b9+OjIwMSCSSEo/4+PgS609NTRVjNTQ0YGRkBBcXF4wfPx6ZmZllzuVVFy5cQFhYGExNTSGVSmFnZ4cpU6YgNzdX6Z7FHampqYiPj4ex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ra0xceJEAEC3bt2watUqTJ48GW+88QZmzpwJqVSKwsJCzJs3D2FhYVrfmiIiIiIiIiIiIiIiYvHod6RSKXbv3o0VK1ZApVLBwcEBy5YtQ0hICMrLy5Gbm4vExETU1NTAzs4Ozz//PJKSkto1g4uLC0QiESQSCfr27YvAwEDMmTMHcrlcGBMUFNRiFm9vb5SWliI5ORkhISGorq5G7969MWXKFCQkJEAsFrdr7rYKDg5Gnz59sGjRImHlj0qlQs+ePbXGVlZWonv37hg2bBjS0tLw008/4c6dO7C3t8e0adOQmJioMX7p0qVYunSpxrG//e1vGDFihNa1ly5diqFDh+Lzzz9HdnY2ampqYGtrCz8/P+zbt69dC4T6mjNnjtax4uJixMXFQSKR4OOPP8ZPP/0EmUwGHx8fFBUVwdzcXBgbFhaGoqIiLFq0CL6+vrh9+zb69++P9957D7GxscI3tIiIiIiIiIiIiIiIGojUarXa0CGI6NE3Ytz3ho5A1CZmYiMUbPQFAASEFeN27b0WziB69PA9pscd32F63PEdpscd32F63PEdpj+KPd/6GzrCY+n25nSD3dts4iyD3dvQOvemfURERERERERERERERKSBxaOHKCQkBBKJRGdbvHixoeM9sMWLFzc5v5CQEEPHe6j4LIiIiIiIiIiIiIjagZHIcK0T4zePHqLMzEzcunVLZ59MJnvIadpfTEwMIiIidPY1/g5PZ8BnQURERERERERERESPKxaPHqJevXoZOkKHkslkf4giWHvgsyAiIiIiIiIiIiJqByJuoGYIfOpEREREREREREREREQkYPGIiIiIiIiIiIiIiIiIBNy2joiIiIiIiIiIiIiIHk0ikaETdEpceUREREREREREREREREQCrjwiIiIiIiIiIiIiIqJHkxHXwBgCnzoREREREREREREREREJWDxqg5qaGiQkJKBfv34wMzODtbU1/P39sXXrVpw7dw4ikajZplAomr2+UqkUxhoZGcHS0hKenp6Ii4tDZWWl3lkaO3bsGCIiImBtbQ2xWAxnZ2ckJSWhpqZG655NNaVSCYVCASsrK525RSIR8vLy9HqGja8rlUoxZMgQrcwKhUJnDjMzM2HM5cuXMX36dPTu3RtisRhyuRxBQUHYu3evMMbR0RErVqzQmaPh9yovL9c4vmnTJjz33HPo3r07zM3N4eLigqioKBw+fFgjX3s9i8ZjG+b4888/a4ybMGECpk6dqnHswoULeOutt9C3b1+IxWLY29tj3LhxKCws1LrPkiVLYGxsjE8++USvXERERERERERERETUOXHbujaIiYlBWVkZMjIy4O7ujqqqKpSUlKCqqgr29vYaBZ6lS5dix44dKCgoEI5ZWlrqdZ8TJ05AKpVCpVLh0KFDSE1NRVZWFpRKJTw8PFrM0qC0tBQBAQEICAjAd999B1tbW+zfvx9z585FYWEhioqK4O3trZF71qxZUKlUyMnJEY7JZDKcO3eurY9NS05ODoKDg6FSqbBy5UqEhYXh0KFDwtwAQCqV4sSJExrniRp9IC00NBR1dXXIzc1F3759cfHiRRQWFmrMv7Xi4+OxbNkyvP3220hOToaDgwMuX76M7du3IyEhATt27GjztfUlEomQlJSE3NzcJsecO3cOPj4+sLKywieffAIPDw/cuXMH//jHP/Dmm2/ixx9/1BifnZ2NuLg4ZGdnY968eR09BSIiIiIiIiIiIqIH1+jfg+nhYfGoGRs3bkRycjJOnz6Nrl27wtPTE1u3bkV+fj7S09MxduxYAPdXtnh5eQnnyeVy4c8SiQQmJiYax/RlY2MDKysryOVyODs7Y/z48fD09MT06dOxZ88eAGgxi1qtRnR0NNzc3LB582YY/d/+kA4ODnB2doanpyfS0tIQHx+vkdHc3By1tbVtyq2vhrnJ5XKkpKQgPT0dRUVFGsUjkUjUZIZr166huLgYSqUS/v7+wryGDh3a5kylpaVITU1Feno63n77beF479694eXlBbVa3eZrt8bMmTOxfPlyzJs3DwMHDtQ5ZsaMGRCJRNi/fz+6desmHB8wYACioqI0xn7//fe4desWFi5ciC+++AIlJSXw9vbu0DkQERERERERERER0eOJ29Y1obKyEpGRkYiKisLx48ehVCoxceJEqNVqyOVybNu2DdXV1Q81k7m5OWJiYrB3715cunQJAFrMUl5ejoqKCsyZM0coHDUYNGgQAgICsG7dug7P3pz6+npkZWUBAExNTfU+TyKRQCKRIC8vD7W1te2SZd26dZBIJJgxY4bOftFDqnL7+Pjg+eefx7vvvquz/7fffsOOHTvw5ptvahSOGvx+O72srCxERkaiS5cuiIyMFJ43ERERERERERER0SNNZGS41ol17tk3o7KyEvX19Zg4cSIcHR3h4eGBGTNmQCKRYPXq1SgpKUGPHj0wZMgQzJ49W+MbOx3J1dUVAITt41rKcvLkSQCAm5ubzuu5ubkJY/R1/fp1oXDTuLVWZGQkJBIJxGIxZs+eDUdHR0RERLR4r5CQEACAiYkJFAoFcnNzYWVlBR8fHyQmJuLo0aOtztLg5MmT6Nu3L0xM/rcob/ny5Rr3v379erP52vIsdFmyZAl27NiB4uJirb7Tp09DrVYL70NzVCoVNm7ciFdeeQUA8Morr2D9+vW4ceNGk+fU1tZCpVJptHt369o+GSIiIiIiIiIiIiJ6bLB41IRBgwZh9OjR8PDwQHh4ONasWYOrV68CAPz8/HDmzBkUFhYiLCwMx44dg6+vL1JSUjo8V8O2aQ0rYPTN0p7brVlYWKC8vFyrtVZaWhrKy8uxfft2uLu7IzMzEzKZrMV7ZWZmCv2hoaH49ddfkZ+fj+DgYCiVSjz99NNQKBQPOMv/iYqKQnl5OVatWoWbN29qPMv2eha6uLu749VXX9W5+qg1v+e6devQr18/DBo0CAAwePBgODg44JtvvmnynCVLlsDS0lKj/ff02tZPgoiIiIiIiIiIiOhBGBkZrnVinXv2zTA2NsauXbuEwkZGRgZcXFxw9uxZAECXLl3g6+uL+Ph47Ny5EwsXLkRKSgrq6jp2dcbx48cB3P+2UYPmsjg7O2ucp+t6DWP0ZWRkBCcnJ63WWnK5HE5OTggMDEROTg4mTZokbMfX3L169eqlMcbMzAxjxozB/PnzUVJSgqlTp2LBggWtzgMA/fv3x5kzZ3Dnzh3hmJWVlc77NpWvLc+iKcnJyTh06BDy8vK0copEIvz4448tXiMrKwvHjh2DiYmJ0CoqKpCdnd3kOQkJCbh+/bpGe9Lp5QedDhERERERERERERE9Blg8aoZIJIKPjw+Sk5Nx+PBhmJqaYsuWLTrHuru7o76+Hrdv3+6wPLdu3cLq1avh5+cHa2vrJsc1zjJ48GC4uroiLS0N9+7d0xh35MgRFBQUIDIyssMy62vo0KHw8vLCokWLHvha7u7uuHnzZpvOjYyMxI0bN7By5coHztEe7O3tMXPmTCQmJuLu3bvCcZlMhqCgIPzlL3/ROddr164BAH744QccOHAASqVSY2WUUqnEvn37miw+icViSKVSjWZkrP/3qIiIiIiIiIiIiIjo8WXS8pDOqaysDIWFhQgMDISNjQ3Kyspw+fJluLm5YeTIkYiMjMQzzzyDHj16oKKiAomJiRg1ahSkUmm7Zbh06RJu376N6upqHDx4EKmpqbhy5Qo2b94sjNEnS1ZWFsaMGYPQ0FAkJCRALpejrKwMc+fOxfDhwxEbG9tumR9EbGwsXnzxRcTFxQmrfNRqNS5cuKA11sbGBlevXkV4eDiioqLw1FNPwcLCAgcOHEBqairGjx+vMf6XX37R2k7OwcFB67rDhw/H3LlzMXfuXPz888+YOHEi7O3tUVlZiaysLIhEIhg95OWKCQkJWLNmDc6ePYtJkyYJx//yl7/Ax8cHQ4cOxcKFC/HUU0+hvr4eu3btwueff47jx48jKysLQ4cOhZ+fn9Z1hwwZgqysLHzyyScPczpERERERERERERE+vu/T7jQw8XiUROkUil2796NFStWQKVSwcHBAcuWLUNISAjKy8uRm5uLxMRE1NTUwM7ODs8//zySkpLaNYOLiwtEIhEkEgn69u2LwMBAzJkzB3K5XBgTFBTUYhZvb2+UlpYiOTkZISEhqK6uRu/evTFlyhQkJCRALBa3a+62Cg4ORp8+fbBo0SJh5Y9KpULPnj21xlZWVqJ79+4YNmwY0tLS8NNPP+HOnTuwt7fHtGnTkJiYqDF+6dKlWLp0qcaxv/3tbxgxYoTWtZcuXYqhQ4fi888/R3Z2NmpqamBraws/Pz/s27evXQuE+pDJZIiPj9eaU9++fXHo0CEsWrQIc+fORWVlJaytreHl5YXPP/8cdXV1+PLLLxEfH6/zuqGhoVi2bBkWL16MLl26PIypEBEREREREREREdFjQKRWq9WGDkFEj74R4743dASiNjETG6Fgoy8AICCsGLdr77VwBtGjh+8xPe74DtPjju8wPe74DtPjju8w/VHs+dbf0BEeS7d35hjs3maBrxns3obGbx4RERERERERERERERGRgMUjAwgJCYFEItHZFi9ebOh4D2zx4sVNzi8kJMTQ8R4qPgsiIiIiIiIiIiIietzwm0cGkJmZiVu3bunsk8lkDzlN+4uJiUFERITOPnNz84ecxrD4LIiIiIiIiIiIiIgegEhk6ASdEotHBtCrVy9DR+hQMpnsD1EEaw98FkRERERERERERET0uGHxiIiIiIiIiIiIiIiIHk1G/PqOIfCpExERERERERERERERkYDFIyIiIiIiIiIiIiIiIhJw2zoiIiIiIiIiIiIiInokqUUiQ0folLjyiIiIiIiIiIiIiIiIiARceURERERERERERERERI8mEdfAGAKfejuqqalBQkIC+vXrBzMzM1hbW8Pf3x9bt27FuXPnIBKJmm0KhaLZ6yuVSmGskZERLC0t4enpibi4OFRWVuqdpbFjx44hIiIC1tbWEIvFcHZ2RlJSEmpqarTu2VRTKpVQKBSwsrLSmVskEiEvL0+vZ9j4ulKpFEOGDNHKrFAodOYwMzMTxly+fBnTp09H7969IRaLIZfLERQUhL179wpjHB0dsWLFCp05Gn6v8vJyjeObNm3Cc889h+7du8Pc3BwuLi6IiorC4cOHNfK117Noamxzv8uFCxcAAB988IFwzMTEBE888QT8/PywYsUK1NbW6pWBiIiIiIiIiIiIiDofrjxqRzExMSgrK0NGRgbc3d1RVVWFkpISVFVVwd7eXqPAs3TpUuzYsQMFBQXCMUtLS73uc+LECUilUqhUKhw6dAipqanIysqCUqmEh4dHi1kalJaWIiAgAAEBAfjuu+9ga2uL/fv3Y+7cuSgsLERRURG8vb01cs+aNQsqlQo5OTnCMZlMhnPnzrX1sWnJyclBcHAwVCoVVq5cibCwMBw6dEiYGwBIpVKcOHFC4zxRo70vQ0NDUVdXh9zcXPTt2xcXL15EYWGhxvxbKz4+HsuWLcPbb7+N5ORkODg44PLly9i+fTsSEhKwY8eONl+7rRrehcZsbGyEPw8YMAAFBQW4d+8eqqqqoFQq8eGHH+Jvf/sblEolLCwsHnZkIiIiIiIiIiIiIv1x5ZFBsHjUBhs3bkRycjJOnz6Nrl27wtPTE1u3bkV+fj7S09MxduxYAPdXtnh5eQnnyeVy4c8SiQQmJiYax/RlY2MDKysryOVyODs7Y/z48fD09MT06dOxZ88eAGgxi1qtRnR0NNzc3LB582YYGd3/D9DBwQHOzs7w9PREWloa4uPjNTKam5ujtra2Tbn11TA3uVyOlJQUpKeno6ioSKN4JBKJmsxw7do1FBcXQ6lUwt/fX5jX0KFD25yptLQUqampSE9Px9tvvy0c7927N7y8vKBWq9t87QfR8C40pfE7ZmdnBw8PD4wZMwaDBg3Cxx9/jA8//PAhJSUiIiIiIiIiIiKixwVLdq1UWVmJyMhIREVF4fjx41AqlZg4cSLUajXkcjm2bduG6urqh5rJ3NwcMTEx2Lt3Ly5dugQALWYpLy9HRUUF5syZIxSOGgwaNAgBAQFYt25dh2dvTn19PbKysgAApqamep8nkUggkUiQl5fXbtuzrVu3DhKJBDNmzNDZ33jV06PO1dUVISEh2Lx5s6GjEBEREREREREREdEjiMWjVqqsrER9fT0mTpwIR0dHeHh4YMaMGZBIJFi9ejVKSkrQo0cPDBkyBLNnz9b4xk5HcnV1BQBh+7iWspw8eRIA4ObmpvN6bm5uwhh9Xb9+XSjcNG6tFRkZCYlEArFYjNmzZ8PR0REREREt3iskJATA/dU2CoUCubm5sLKygo+PDxITE3H06NFWZ2lw8uRJ9O3bFyYm/1ust3z5co37X79+vdl8bXkWLXnyySc1rj9gwAC9znN1dW12q8Ha2lqoVCqNdu9uXTulJiIiIiIiIiIiItKPWiQyWOvMWDxqpUGDBmH06NHw8PBAeHg41qxZg6tXrwIA/Pz8cObMGRQWFiIsLAzHjh2Dr68vUlJSOjxXw7ZpDStg9M3SntutWVhYoLy8XKu1VlpaGsrLy7F9+3a4u7sjMzMTMpmsxXtlZmYK/aGhofj111+Rn5+P4OBgKJVKPP3001AoFA84y/+JiopCeXk5Vq1ahZs3b2o8y/Z6Fi0pLi7WuP62bdv0Ok+tVje7WmrJkiWwtLTUaP89vba9YhMRERERERERERHRI4zFo1YyNjbGrl27hMJGRkYGXFxccPbsWQBAly5d4Ovri/j4eOzcuRMLFy5ESkoK6uo6dtXG8ePHAdz/tlGD5rI4OztrnKfreg1j9GVkZAQnJyet1lpyuRxOTk4IDAxETk4OJk2aJGzH19y9evXqpTHGzMwMY8aMwfz581FSUoKpU6diwYIFrc4DAP3798eZM2dw584d4ZiVlZXO+zaVry3PoiV9+vTRuL6Dg4Ne5x0/fhx9+vRpsj8hIQHXr1/XaE86vdxesYmIiIiIiIiIiIj0IzIyXOvEOvfs20gkEsHHxwfJyck4fPgwTE1NsWXLFp1j3d3dUV9fj9u3b3dYnlu3bmH16tXw8/ODtbV1k+MaZxk8eDBcXV2RlpaGe/fuaYw7cuQICgoKEBkZ2WGZ9TV06FB4eXlh0aJFD3wtd3d33Lx5s03nRkZG4saNG1i5cuUD5zC0H3/8ETt27EBoaGiTY8RiMaRSqUYzMtb/u1NERERERERERERE9PgyaXkINVZWVobCwkIEBgbCxsYGZWVluHz5Mtzc3DBy5EhERkbimWeeQY8ePVBRUYHExESMGjUKUqm03TJcunQJt2/fRnV1NQ4ePIjU1FRcuXIFmzdvFsbokyUrKwtjxoxBaGgoEhISIJfLUVZWhrlz52L48OGIjY1tt8wPIjY2Fi+++CLi4uKEVT5qtRoXLlzQGmtjY4OrV68iPDwcUVFReOqpp2BhYYEDBw4gNTUV48eP1xj/yy+/aG0np2v1zvDhwzF37lzMnTsXP//8MyZOnAh7e3tUVlYiKysLIpEIRkbtX4s9e/asVr7+/fsLf254Fxrr0aMHunTpAgCor6/HhQsXcO/ePVRVVUGpVOLDDz/E4MGDMW/evHbPS0RERERERERERESPPxaPWkkqlWL37t1YsWIFVCoVHBwcsGzZMoSEhKC8vBy5ublITExETU0N7Ozs8PzzzyMpKaldM7i4uEAkEkEikaBv374IDAzEnDlzIJfLhTFBQUEtZvH29kZpaSmSk5MREhKC6upq9O7dG1OmTEFCQgLEYnG75m6r4OBg9OnTB4sWLRJW/qhUKvTs2VNrbGVlJbp3745hw4YhLS0NP/30E+7cuQN7e3tMmzYNiYmJGuOXLl2KpUuXahz729/+hhEjRmhde+nSpRg6dCg+//xzZGdno6amBra2tvDz88O+ffvatUDYYM6cOVrHiouLhT+7uLho9e/btw/PPvssAODYsWPo2bMnjI2NYWlpCXd3dyQkJGD69OmPzO9LRERERERERERE1KRmvt1OHUekVqvVhg5BRI++EeO+N3QEojYxExuhYKMvACAgrBi3a++1cAbRo4fvMT3u+A7T447vMD3u+A7T447vMP1R7PnW39ARHks1xRsMdu+uvuEGu7ehceURERERERERERERERE9mjrgcyHUMj71R0hISAgkEonOtnjxYkPHe2CLFy9ucn4hISGGjvdQ8VkQERERERERERER0aOKK48eIZmZmbh165bOPplM9pDTtL+YmBhERETo7DM3N3/IaQyLz4KIiIiIiIiIiIioZWp+88ggWDx6hPTq1cvQETqUTCb7QxTB2gOfBRERERERERERERE9qrhtHREREREREREREREREQm48oiIiIiIiIiI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/z5Eovv51Wo1FixYgDVr1uDatWvw8fHB559/jv79+wvX+e233/DWW2/h22+/hZGREUJDQ5Geng6JRCKMOXr0KN58803861//grW1Nd566y3ExcW1+5w697orIiIiIiIiIiIiIiKiB/Dxxx/j888/x2effYbjx4/j448/RmpqKjIyMoQxqamp+PTTT/HXv/4VZWVl6NatG4KCgnD79m1hzMsvv4xjx45h165d+Pvf/47du3fjjTfeEPpVKhUCAwPh4OCAgwcP4pNPPsEHH3yA1atXt/ucuPKIiIiIiIiIiIiIiIgeSerH4NtDJSUlGD9+PP70pz8BABwdHbFu3Trs378fwP1VRytWrMD777+P8ePHAwC++OIL2NraIi8vD5MnT8bx48exY8cO/Otf/8IzzzwDAMjIyMDYsWOxdOlS2NnZYe3atairq0N2djZMTU0xYMAAlJeXY/ny5RpFpvbw6D91IiIiIiIiIiIiIiKih6y2thYqlUqj1dbWao3z9vZGYWEhTp48CQA4cuQI9uzZg5CQEADA2bNnceHCBQQEBAjnWFpaYtiwYdi3bx8AYN++fbCyshIKRwAQEBAAIyMjlJWVCWP8/PxgamoqjAkKCsKJEydw9erVdp07i0dERERERERERERERES/s2TJElhaWmq0JUuWaI179913MXnyZLi6uqJLly7w9PREbGwsXn75ZQDAhQsXAAC2trYa59na2gp9Fy5cgI2NjUa/iYkJZDKZxhhd12h8j/bCbeuIiIiIiIiIiIiIiOjRZMBt6xISEjBnzhyNY2KxWGvc+vXrsXbtWnz11VfCVnKxsbGws7PDlClTHlbcdsXiERERERERERERERER0e+IxWKdxaLfmzdvnrD6CAA8PDzw888/Y8mSJZgyZQrkcjkA4OLFi+jZs6dw3sWLFzF48GAAgFwux6VLlzSuW19fj99++004Xy6X4+LFixpjGv7eMKa9cNs6IiIiIiIiIiIiIiJ6JKlFIoM1fdXU1MDISLPcYmxsjHv37gEA+vTpA7lcjsLCQqFfpVKhrKwMw4cPBwAMHz4c165dw8GDB4Ux//znP3Hv3j0MGzZMGLN7927cuXNHGLNr1y64uLige/furX+4zej0xaOamhokJCSgX79+MDMzg7W1Nfz9/bF161acO3cOIpGo2aZQKJq9vlKpFMYaGRnB0tISnp6e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/pDTPJrs7OxQXl7ebD8RERERERERERER0aOIxaMO0KtXL0NH6FAymewPUQTrSCYmJnBycjJ0DCIiIiIiIiIiIqLHmhoiQ0folDr3uisiIiIiIiIiIiIiIiLS0Kri0RdffIHa2tqOykJEREREREREREREREQG1qri0WuvvYbr1693VBYiIiIiIiIiIiIiIiKBWmRksNaZtWr2arW6o3IQERERERERERERERHRI8CktSeIRPw4FRERERERERERERERdTw1WJMwhFYXj0aPHg0Tk+ZPO3ToUJsDERERERERERERERERkeG0etO+oKAgjB8/vtn2qKqpqUFCQgL69esHMzMzWFtbw9/fH1u3bsW5c+cgEomabQqFotnrK5VKYayRkREsLS3h6emJuLg4VFZW6p2lsWPHjiEiIgLW1tYQi8VwdnZGUlISampqtO7ZVFMqlVAoFLCystKZWyQSIS8vT69n2Pi6UqkUQ4YM0cqsUCh05jAzMxPGXL58GdOnT0fv3r0hFoshl8sRFBSEvXv3AgAmT56M4OBgjevu2LEDIpEIH3zwgcbxDz74AL1799Y4tmTJEhgbG+OTTz7RmkNDPjc3N62+DRs2QCQSwdHRUavv1q1bkMlkeOKJJ1BbW9vsc9Ll8OHDCA8Ph62tLczMzNC/f39MmzYNJ0+e1BiXm5uLIUOGoGvXrrCwsIC/vz/+/ve/a4xp+N0HDBiAu3fvavRZWVlBoVCgrq4OTzzxBD766COdeVJSUmBra4s7d+60ei5ERERERERERERE9MfV6pVH8+bNg42NTUdk6XAxMTEoKytDRkYG3N3dUVVVhZKSElRVVcHe3l6jwLN06VLs2LEDBQUFwjFLS0u97nPixAlIpVKoVCocOnQIqampyMrKglKphIeHR4tZGpSWliIgIAABAQH47rvvYGtri/3792Pu3LkoLCxEUVERvL29NXLPmjULKpUKOTk5wjGZTIZz58619bFpycnJQXBwMFQqFVauXImwsDAcOnRImBsASKVSnDhxQuO8xlsehoaGoq6uDrm5uejbty8uXryIwsJCYf6jRo3CO++8g/r6emGlW1FREezt7aFUKjWuW1RUhFGjRmkcy87ORlxcHLKzszFv3jytOXTr1g2XLl3Cvn37MHz4cOF4VlaWViGqwaZNmzBgwACo1Wrk5eVh0qRJejyt+/7+978j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T5+O5ORkiMXiLs19p8LDwzFkyBAsWbIEq1evBnCzQDJo0CCtvlVVVRgwYAD8/PyQlZWFn376CU1NTXBwcMDMmTORkpLS7liNjY34+OOP26zeRkVFYfny5cjIyICzszMOHz6MJUuWIDExEVVVVbCxsYG3tzfee+894ZrIyEgUFxdj6dKleP7556FSqeDg4IAnn3wSb731ltAvOzsbI0aMwOrVq/HGG2/A0NAQo0aNwubNmzFx4kS9n9fhw4dRWloKAFrbBp45c0Zja0MiIiIiIiIiIiIiIpFarVb3dAgi6v2emPh9T0cguiOmYgMUbhgDAAiO3oP6Bv73KtT38D2mvo7vMPV1fIepr+M7TH0d32G6X+z9KqinI/RJ+ytVPTb2aLeu20Gsr+E3j4iIiIiIiIiIiIiIiEjA4lEvFhERAYlEorNlZGT0dLy7lpGR0eb8IiIi7lmOdevWtZlj+PDh9ywHEREREREREREREVFvwG8e9WI5OTmoq6vTec7Kyuoep+l68fHxiImJ0XnOzMzsnuV45pln4Ofnp/OcsbHxPctBRERERERERERERJrUEPV0hAcSi0e9mL29fU9H6FZWVla9oghmbm4Oc3Pzno5BRERERERERERERNQrsHhERERERERERERERES9klrNlUc9gd88IiIiIiIiIiIiIiIiIgGLR0RERERERERERERERCTgtnVERERERERERERERNQrqcFt63oCVx4RERERERERERERERGRgCuPiIiIiIiIiIiIiIioV2pR93SCBxNXHnWj2tpaJCcnY+jQoTA1NYWNjQ2CgoKwZcsWnD17FiKRqN2mUCjavb9SqRT6GhgYwMLCAl5eXliwYAGqqqr0znKr8vJyxMTEwMbGBmKxGHK5HIsWLUJtba3WmG01pVIJhUIBS0tLnblFIhE2b96s1zO89b5SqRQ+Pj5amRUKhc4cpqamQp+LFy9i1qxZGDx4MMRiMWQyGcLCwrBv3z69crRaunQpDA0N8c477+g8f/78ebzyyitwdnaGWCyGg4MDJk6ciKKiIo1+R44cweTJkzFw4ECYmprikUcewcyZM3HixAmNfvn5+fDx8UG/fv1gbm6OoKAgfP311xp9bv9NBg4ciKioKJw+fVqj3/79+/Hkk0+if//+kEqlCAwMRF1dXafmT0RERERERERERET3PxaPulF8fDw2btyIlStX4scff8T27dsRHR2Ny5cvw8HBAVVVVUJLTEzE8OHDNY5NmTJFr3GOHz+Oc+fO4V//+heSkpJQWFiIRx99FD/88INeWVqVlJTAz88PjY2N+Oabb3DixAksWbIECoUCISEhaGxshL+/v0bGmJgYhIeHaxzz9/fv0ueYl5eHqqoqHDx4EAEBAYiOjtaYGwBIpVKNDFVVVfjPf/4jnI+KisKRI0eQn5+PEydOoKCgAGPHjtWYvz7Wrl2LBQsWYO3atVrnzp49C29vb3z33Xd455138MMPP2D79u0YN24c5syZI/T7+uuv8fjjj6OhoQHr1q1DZWUlPv74Y1hYWGDhwoVCv7/+9a94+eWXMWXKFBw7dgwHDhzAE088gcjISLz77rta47e+B1988QXKy8sxceJE/PHHHwBuFo7Cw8MRGhqKAwcO4F//+hf+8pe/wMCA/wogIiIiIiIiIiIiIk3ctq4LbNiwAampqTh16hT69esHLy8vbNmyBQUFBVixYgUmTJgAAHBycoK3t7dwnUwmE/4skUhgZGSkcUxftra2sLS0hEwmg1wuR2RkJLy8vDBr1izs3bsXADrMolarMWPGDLi5uWHjxo1CUcHR0RFyuRxeXl7IyspCUlKSRkYzMzM0NDTcUW59tc5NJpMhPT0dK1aswK5du+Dh4SH0EYlEbWa4du0a9uzZA6VSiaCgIGFevr6+ncrx/fffo66uDmlpafjoo49QXFysUSibPXs2RCIRDhw4gP79+wvHhw8fjri4OAA3V4C99NJLmDBhAjZt2iT0GTJkCPz8/HDt2jUANwt5y5cvxz/+8Q+88sorQr8lS5agvr4e8+fPR2RkJBwcHIRzre/BoEGDsGjRIkybNg2nTp2Cq6srEhIS8Oqrr+J///d/hf6urq6dmj8RERERERERERHRvaaGqKcjPJC47OAuVVVVITY2FnFxcaisrIRSqcSkSZOgVqshk8mwdetW1NTU3NNMZmZmiI+Px759+1BdXQ0AHWYpKytDRUUF5s+fr7UaxdPTE8HBwVi/fn23Z29Pc3MzcnNzAQAmJiZ6XyeRSCCRSLB582Y0NDTc8fi5ubmIjY2FsbExYmNjhSwAcOXKFWzfvh1z5szRKBy1at3C79tvv8WlS5ewYMECnWO09lu/fj0kEglefvllrT6JiYloamrCl19+2WZWMzMzAEBjYyOqq6tRWloKW1tb+Pv7Y+DAgQgKChIKi0REREREREREREREt2Lx6C5VVVWhubkZkyZNgpOTEzw8PDB79mxIJBKsWbMGxcXFsLa2ho+PDxISEjr9jZ07NWzYMAA3t1ID0GGW1m/tuLm56byfm5ub1vd4OnL9+nWhcHNr66zY2FhIJBKIxWIkJCTAyckJMTExHY4VEREBADAyMoJCoUB+fj4sLS0REBCAlJQUHDt2TO8MKpUKGzZswAsvvAAAeOGFF/D555/j999/BwCcOnUKarVaeO5tOXnyJAB02O/EiRMYOnSoziKZnZ0dpFJpm79HVVUVli1bBnt7e7i6ugrfPnrzzTcxc+ZMbN++HaNGjcL48eOFPLdraGiASqXSaC1/NLabmYiIiIiIiIiIiKirqdWiHmsPMhaP7pKnpyfGjx8PDw8PTJ48GR9++CGuXr0KAAgMDMTp06dRVFSE6OholJeXY8yYMUhPT+/2XGq1GsDN7dw6k6X1uq5gbm6OsrIyrdZZWVlZKCsrw7Zt2+Du7o6cnBxYWVl1OFZOTo5wPioqCufOnUNBQQHCw8OhVCoxatQoKBQKvTKsX78eQ4cOhaenJwBg5MiRcHR0xGeffQZA/+fWmefb2d/i4YcfRv/+/WFnZ4cbN27gyy+/hImJCVpaWgAAL7/8Ml566SVhC0JXV1ed324CgKVLl8LCwkKj/XpqXafyEBEREREREREREVHfxOLRXTI0NMTOnTuFwsbKlSvh6uqKM2fOAACMjY0xZswYJCUlYceOHUhLS0N6ejoaG7t3FUdlZSWAm982atVeFrlcrnGdrvu19tGXgYEBXFxctFpnyWQyuLi4IDQ0FHl5eZgyZYqwHV97Y9nb22v0MTU1RUhICBYuXIji4mK8+OKLWLx4sV4ZcnNzUV5eDiMjI6FVVFQIxZdHHnkEIpEIP/74Y7v3aX2G+vQ7ffq0zvfk3LlzUKlUWr/Hnj17cOzYMahUKpSVlcHPzw8AMGjQIACAu7u7Rn83Nzf8/PPPOsdPTk7G9evXNdrDLtPazUxERERERERERETU1dTqnmsPMhaPuoBIJEJAQABSU1Nx5MgRmJiYYNOmTTr7uru7o7m5GfX19d2Wp66uDmvWrEFgYCBsbGza7HdrlpEjR2LYsGHIysoSVqq0Onr0KAoLCxEbG9ttmfXl6+sLb29vLFmy5K7v5e7ujhs3bnTY74cffsDBgwehVCo1VjYplUrs378fP/74I6ysrBAWFoZVq1bpvOe1a9cAAKGhoXjooYeQmZmpc6zWflOnTsXvv/+ODz74QKvPsmXLYGxsjKioKI3jQ4YMwdChQ2Fubq5x3MnJCXZ2djh+/LjG8RMnTsDR0VFnDrFYDKlUqtEMDPX/zhQRERERERERERER9V1GPR2grystLUVRURFCQ0Nha2uL0tJSXLx4EW5ubhg7dixiY2Px2GOPwdraGhUVFUhJScG4ceMglUq7LEN1dTXq6+tRU1ODQ4cOITMzE5cuXcLGjRuFPvpkyc3NRUhICKKiopCcnAyZTIbS0lIkJiZi9OjRmDdvXpdlvhvz5s3Dc889hwULFgiri9RqNc6fP6/V19bWFlevXsXkyZMRFxeHESNGwNzcHAcPHkRmZiYiIyM7HC83Nxe+vr4IDAzUOufj44Pc3Fy88847WLVqFQICAuDr64u0tDSMGDECzc3N2LlzJ9577z1UVlaif//+yMnJweTJk/HMM8/g1VdfhYuLCy5duoTPP/8cP//8Mz799FOMHj0ac+fOxWuvvYbGxkY8++yzaGpqwscff4wVK1YgOzsbDg4Oej0vkUiE1157DYsXL4anpydGjhyJ/Px8/Pjjj9iwYYNe9yAiIiIiIiIiIiKiBweLR3dJKpVi9+7dyM7OhkqlgqOjI5YvX46IiAiUlZUhPz8fKSkpqK2thZ2dHZ5++mksWrSoSzO4urpCJBJBIpHA2dkZoaGhmD9/PmQymdAnLCyswyz+/v4oKSlBamoqIiIiUFNTg8GDB2P69OlITk6GWCzu0tx3Kjw8HEOGDMGSJUuwevVqAIBKpRK2Z7tVVVUVBgwYAD8/P2RlZeGnn35CU1MTHBwcMHPmTKSkpLQ7VmNjIz7++GMkJSXpPB8VFYXly5cjIyMDzs7OOHz4MJYsWYLExERUVVXBxsYG3t7eeO+994RrIiMjUVxcjKVLl+L555+HSqWCg4MDnnzySbz11ltCv+zsbIwYMQKrV6/GG2+8AUNDQ4waNQqbN2/GxIkTO/XM5s2bh/r6eiQkJODKlSvw9PTEzp07MXTo0E7dh4iIiIiIiIiIiOheaoGopyM8kERq9YO+cx8R6eOJid/3dASiO2IqNkDhhjEAgODoPahvaOngCqLeh+8x9XV8h6mv4ztMfR3fYerr+A7T/WLvV0E9HaFPKvqh+z4B05HxHqY9NnZP48ojIiIiIiIiIiIiIiLqldRqrjzqCQY9HYDaFhERAYlEorNlZGT0dLy7lpGR0eb8IiIi7lmOdevWtZlj+PDh9ywHEREREREREREREVFvwJVHvVhOTg7q6up0nrOysrrHabpefHw8YmJidJ4zMzO7ZzmeeeYZ+Pn56TxnbGx8z3IQEREREREREREREfUGLB71Yvb29j0doVtZWVn1iiKYubk5zM3NezoGEREREREREREREd1Gre7pBA8mbltHREREREREREREREREAq48IiIiIiIiIiIiIiKiXkkNUU9HeCBx5REREREREREREREREREJuPKIiIiIiIiIiIiIiIh6pRZ+86hHcOURERERERERERERERERCVg8IiIiIiIiIiIiIiIiIgGLR71IbW0tkpOTMXToUJiamsLGxgZBQUHYsmULzp49C5FI1G5TKBTt3l+pVAp9DQwMYGFhAS8vLyxYsABVVVV6Z7lVeXk5YmJiYGNjA7FYDLlcjkWLFqG2tlZrzLaaUqmEQqGApaWlztwikQibN2/W6xneel+pVAofHx+tzAqFQmcOU1NToc/Fixcxa9YsDB48GGKxGDKZDGFhYdi3b59eOZycnIT7Ghoaws7ODjNmzMDVq1eFPq3P5tq1a8KxP/74A1lZWfDw8ICpqSkGDBiAiIgIrXFb5+Dm5qY19hdffAGRSAQnJ6cO55yTk6PXfIiIiIiIiIiIiIh6glot6rH2IOM3j3qR+Ph4lJaWYuXKlXB3d8fly5dRXFyMy5cvw8HBQaPAs2zZMmzfvh2FhYXCMQsLC73GOX78OKRSKVQqFQ4fPozMzEzk5uZCqVTCw8OjwyytSkpKEBwcjODgYHzzzTcYOHAgDhw4gMTERBQVFWHXrl3w9/fXyD137lyoVCrk5eUJx6ysrHD27Nk7fWxa8vLyEB4eDpVKhdWrVyM6OhqHDx8W5gYAUqkUx48f17hOJPrvvwyioqLQ2NiI/Px8ODs748KFCygqKtKYf0fS0tIwc+ZM/PHHHzhx4gT+53/+B6+++ir++c9/6uyvVqsxdepUFBYW4p133sH48eOhUqmwatUqjB07Fl988QWeffZZoX///v1RXV2N/fv3Y/To0cLx3NxcDB48WOv+uuas7ztDRERERERERERERA8OFo96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KXbv3o3s7GyoVCo4Ojpi+fLliIiIQFlZGfLz85GSkoLa2lrY2dnh6aefxqJFi7o0g6urK0QiESQSCZydnREaGor58+cLLypwcz/FjrL4+/ujpKQEqampiIiIQE1NDQYPHozp06cjOTlZr//x3Qvh4eEYMmQIlixZgtWrVwMAVCoVBg0apNW3qqoKAwYMgJ+fH7KysvDTTz+hqakJDg4OmDlzJlJSUvQed9GiRVq/3csvv4z3339f+OepU6dqXffLL790mFEmk8HZ2RmHDx/GkiVLkJiYiKqqKtjY2MDb2xvvvfee3jmJiIiIiIiIiIiISNv48ePxww8/aBx76aWXMGzYMCQlJcHBwQHGxsYoKipCVFQUgJsLBn7++WeMHj0aADB69GgsWbIE1dXVsLW1BQDs3LkTUqkU7u7uQp+tW7dqjLNz507hHl1JpFar1V1+VyK67zwx8fuejkB0R0zFBijcMAYAEBy9B/UNLR1cQdT78D2mvo7vMPV1fIepr+M7TH0d32G6X+z9KqinI/RJH+zoubFfDr3za8eOHYuRI0ciOzsbADBr1ixs3boVCoUCUqkUr7zyCgCguLgYwM2VSiNHjoSdnR0yMzNx/vx5/OlPf8Kf//xnZGRkAADOnDmDRx99FHPmzEFcXBy+++47vPrqq/jmm28QFhZ2V3O9HVceERERERERERERERERdaOsrCwYGBggKioKDQ0NCAsLE3bAAgBDQ0N8/fXXmDVrFkaPHo3+/ftj+vTpSEtLE/oMGTIE33zzDRISErBixQo8/PDDyMnJ6fLCEcDi0QMpIiICe/bs0XkuJSWlU1uu9UYZGRlCJfZ2Y8aMwbZt2+5JjnXr1uHll1/Wec7R0RHl5eX3JAcRERERERERERFRX9VX905TKpUa/2xqaopVq1Zh1apVbV7j6OiotS3d7caOHYsjR450RcR2sXj0AMrJyUFdXZ3Oc1ZWVvc4TdeLj49HTEyMznNd/dGw9jzzzDPw8/PTec7Y2Pie5SAiIiIiIiIiIiIi6gwWjx5A9vb2PR2hW1lZWfWKIpi5uTnMzc17OgYRERERERERERERUaeweERERERERERERERERL1SX922rq8z6OkARERERERERERERERE1Htw5REREREREREREREREfVKLVx51CO48oiIiIiIiIiIiIiIiIgEXHlERERERERERERE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1LAadp0aVsPJwLRjVxsGzFtUw4lJDetnset+jPMJkWjp4pGIOKWmpgbV1dUoLCxEMNhy581PPvkE6enpyMvL67Wx0nsaGxtBEgMHDgQAVFVVYfPmzcjPz8f06dPDjrGZ3PlNDScfNayGXaeG1bDr1LAaTgaxduxyw4B5i2o4calh/Sx23Y9tPiESDV08EhERX02bNg1z585FUVER6uvrkZeXh759++LkyZP47W9/i+Li4ohjTSZ3Il5Tw+I6NSyuU8OSDEw7VsOSKNSwuE7zCZGugn5vgIiI/Ljt27cP119/PYCWt/CPGDECVVVVWL9+PZ588slux86ePRvr168HANTX12PixIl47LHHMGfOHKxdu7bXt10EUMPiPjUsrlPDkgxMO1bDkijUsLhO8wmRrnTxSEREfNXQ0IC0tDQAwNatWzF37lwEg0FcffXVqKqq6naszeROxCtqWFynhsV1aliSgWnHalgShRoW12k+IdKVLh6JiIivxowZg9deew3Hjh1DWVkZpk2bBgA4fvw40tPTux1rM7kT8YoaFtepYXGdGpZkYNqxGpZEoYbFdZpPiHSli0ciIuKr+++/H/fccw9Gjx6NiRMn4pprrgHQMuGaMGFCt2NtJnciXlHD4jo1LK5Tw5IMTDtWw5Io1LC4TvMJka4CJOn3RoiIyI9bTU0NqqurUVhYiGCw5XUNn3zyCdLT05GXlxdx3KZNmzB//nw0NTVhypQp2Lp1KwDgkUcewc6dO7Fly5a4bL+IGhbXqWFxnRqWZGDSsRqWRKKGxXWaT4h0pItHIiLiNNPJnUiiUMPiOjUsrlPD4jo1LK5Tw5IM1LEkI108EhERERERERERERERkRD9zSMREREREREREREREREJ0cUjERERERERERERERERCdHFIxEREREREREREREREQnRxSMREREREREREREREREJ0cUjERERERERERERERERCdHFIxEREREREQc98MADCAQCXf7l5eWFPqeiogLz589HVlYWUlNTkZ2djdmzZ+Pzzz/3cctFRERERCTRpfi9ASIiIiIiImJm3LhxePvttzt8LCWl5de8H374AVOnTsVll12GV199FaNGjcLXX3+NLVu2oL6+3oetFRERERERV+jikYiIiIiISALbtGkTSkpK8OWXX2LgwIGYMGECXn/9dQAtF4pGjhwZdtzBgwdx5MgRbN++HTk5OQCAnJwcXHfddXHbdhERERERcZNuWyciIiIiIpKgqqur8Q//8A9YsmQJDh8+jHfffRdz584FyR7HDhs2DMFgEJs2bUJTU1MctlZERERERJKFLh6JiIiIiIgkqOrqapw/fx5z587F6NGjMX78eCxbtgyDBw8GAPz3f/83Bg8e3OFfUVERAOCiiy7Ck08+ifvvvx+ZmZm44YYbUFpaiq+++srPXRIREREREQcEGM1L1kRERERERCTumpqaMH36dHzyySeYPn06pk2bhnnz5iEzMxMPPPAANmzYgD//+c8dxqSnp2P48OGh5f/93//Fu+++i48//hhvvPEG/ud//gd//vOfMXXq1HjvjoiIiIiIOEIXj0RERERERBIYSXz44YfYunUrNm/ejJqaGuzatQsvvPACXnvtNZSXl8f0WNOnT8f//d//YceOHb230SIiIiIi4jTdtk5ERERERCSBBQIBXHfddSgpKcGnn36Kfv36YfPmzcaPlZeXh7Nnz3q8lSIiIiIikkxS/N4AERERERERCW/Xrl3Yvn07pk2bhuHDh2PXrl04ceIE8vPzsWvXLpw/fx41NTUdxgQCAYwYMQLl5eVYtWoVFixYgLFjx6Jfv37YsWMHnnvuOdx7770+7ZGIiIiIiLhAF49EREREREQSVHp6Onbu3Ik1a9bgu+++Q05ODh577DHcdNNN2LVrFw4ePIhRo0Z1GNO/f3+cO3cO2dnZGD16NEpKSlBZWYlAIBBavuuuu3zaIxERERERcYH+5pGIiIiIiIiIiIiIiIiE6G8eiYiIiIiIiIiIiIiISIguHomIiIiIiIiIiIiIiEiILh6JiIiIiIiIiIiIiIhIiC4eiYiIiIiIiIiIiIiISIguHomIiIiIiIiIiIiIiEiILh6JiIiIiIiIiIiIiIhIiC4eiYiIiIiIiIiIiIiISIguHomIiIiIiIiIiIiIiEiILh6JiIiIiIiIiIiIiIhIiC4eiYiIiIiIiIiIiIiISIguHomIiIiIiIiIiIiIiEjI/wP2v43qtYJo1QAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Make a single heatmap that includes all the years\n", + "# Create a df that contains the emissions of each ST for each year\n", + "# The rows are the sST and the columns are sES\n", + "# Each intersection should be divided in 7 columns, one for each year\n", + "# The value of each intersection should be the emissions of the ST for that year\n", + "# The heatmap should have a color scale that goes from 0 to the maximum value of the emissions\n", + "\n", + "# Create a df that contains the emissions of each ST for each year in the residential sector\n", + "\n", + "emissions_2020_RES = vEmiCO2ST_HEATMAP_2020_RES.pivot(index='sST', columns='sES', values='vEmiCO2ST')\n", + "emissions_2025_RES = vEmiCO2ST_HEATMAP_2025_RES.pivot(index='sST', columns='sES', values='vEmiCO2ST')\n", + "emissions_2030_RES = vEmiCO2ST_HEATMAP_2030_RES.pivot(index='sST', columns='sES', values='vEmiCO2ST')\n", + "emissions_2035_RES = vEmiCO2ST_HEATMAP_2035_RES.pivot(index='sST', columns='sES', values='vEmiCO2ST')\n", + "emissions_2040_RES = vEmiCO2ST_HEATMAP_2040_RES.pivot(index='sST', columns='sES', values='vEmiCO2ST')\n", + "emissions_2045_RES = vEmiCO2ST_HEATMAP_2045_RES.pivot(index='sST', columns='sES', values='vEmiCO2ST')\n", + "emissions_2050_RES = vEmiCO2ST_HEATMAP_2050_RES.pivot(index='sST', columns='sES', values='vEmiCO2ST')\n", + "\n", + "# Create a df that contains the emissions of each ST for each year\n", + "emissions_RES = pd.concat([emissions_2020_RES, emissions_2025_RES, emissions_2030_RES, emissions_2035_RES, emissions_2040_RES, emissions_2045_RES, emissions_2050_RES], axis=1)\n", + "\n", + "# replace NaN values with 0\n", + "emissions_RES.fillna(0, inplace=True)\n", + "\n", + "# Increase the size of the plot in sucha way that all the years are visible an sST and sES are readable\n", + "plt.figure(figsize=(20, 8))\n", + "# Create a heatmap\n", + "sns.heatmap(emissions_RES, cmap='coolwarm',vmin=0, vmax=emissions_RES.max().max())\n", + "#Insert a separator between the years\n", + "plt.axvline(x=[12], color='white')\n", + "plt.axvline(x=[24], color='white')\n", + "plt.axvline(x=[36], color='white')\n", + "plt.axvline(x=[48], color='white')\n", + "plt.axvline(x=[60], color='white')\n", + "plt.axvline(x=[72], color='white')\n", + "\n", + "\n", + "\n", + "# Add a label to each axvline\n", + "plt.text(6, -0.5, '2020', fontsize=12, color='black')\n", + "plt.text(18, -0.5, '2025', fontsize=12, color='black')\n", + "plt.text(30, -0.5, '2030', fontsize=12, color='black')\n", + "plt.text(42, -0.5, '2035', fontsize=12, color='black')\n", + "plt.text(54, -0.5, '2040', fontsize=12, color='black')\n", + "plt.text(66, -0.5, '2045', fontsize=12, color='black')\n", + "plt.text(78, -0.5, '2050', fontsize=12, color='black')\n", + "\n", + "# Rotate the x axis labels\n", + "plt.title('CO2 emissions of each STRes (vQSTInTE + vQSTOut) for each year [ktCO2]', y=1.05)\n", + "#move the title more to the top\n", + "plt.xlabel('sES')\n", + "plt.ylabel('sST')\n", + "\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Graph total STRes CO2 emissions for each year\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "emissions = [TotEmiSTRes_2020, TotEmiSTRes_2025, TotEmiSTRes_2030, TotEmiSTRes_2035, TotEmiSTRes_2040, TotEmiSTRes_2045, TotEmiSTRes_2050]\n", + "cap = data_input['pEmiCO2CapOth']\n", + "plt.plot(years, emissions, marker='o')\n", + "plt.plot(years, cap.pEmiCO2CapOth, marker='o')\n", + "plt.title('Total CO2 emissions of the Residential + Services Sectors for each year [MtCO2]')\n", + "plt.legend(['Total CO2 emissions', 'CO2 Cap'])\n", + "plt.xlabel('Year')\n", + "plt.ylabel('[MtCO2]')\n", + "plt.show()\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "TotEmiSTRes_2045" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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fv75ZwwaNAgSiQRnzpzBmzdv4OXlJeZxdHREjRo1cOLECQDAiRMn4OLigqpVq4p5vL29kZGRgUuXLol53i1DnkdeRlFwQKgIpFIpDh48KA4ILF++HA4ODrh16xYAQEdHB25ubpg6dSoOHDiAOXPmICwsTO0AhqakpKQAeLteoZymYrGzs4ODgwP69++PIUOGIDAwUDz35MkT7Ny5EytWrIC2tja0tbVhbW2NnJwcREREaOTe3jVx4kRkZWVhxYoVKs/r6urC3t5ePGxsbDRav6WlJezt7dG+fXtERkYiMDBQXKYPAIyNjZGenq503bNnzwBAYT8i4G3b2tvbw9nZGQMHDkS/fv0wd+7cfGMwMjJSuEd7e/siD0rZ2NgolaFOSEgI0tPTFY7q9n2KVB8RERERERERERHRh5BoSUrtUPUl+fnz5xcY4y+//IJnz55hwIABAIB79+5BV1cXpqamCvmqVq2Ke/fuiXneHQySn5efyy9PRkYGsrKyitSOHBAqIolEgtatW2P27Nn4888/oauri507d6rM6+TkhJycHLx69arE4snKysLq1avh7u6uND1N07GMHj0aFy9eFO83Ojoa1atXx7lz5xRmmyxatAhRUVHIzc0tdl2qyGQyfP3115g7d26p79X0vmbNmsHV1VVhAMfBwQF37txR2hTs7Nmz0NfXR40aNfItU74cXXmip6cHY2NjhYPLxREREREREREREVFFpepL8iEhIQVeFx4ejg4dOsDKyqoUoiwe7iFUBElJSTh06BDat2+PKlWqICkpCQ8fPkS9evXQtm1bBAUFoUmTJjA3N8fly5cxbdo0tGvXDsbGxhqL4cGDB3j16hWeP3+OM2fOYMGCBXj06BF27Ngh5impWAwNDTF06FDMmjULXbp0QXh4OAICAlC/fn2FfDY2NggJCUFsbCz8/PwKLDc9PV1p2TJzc3OVM3yGDRuGJUuWYOPGjWjevHmx70UTgoOD0bVrV0yZMgXW1tbw9vaGg4MDgoKC8M0338DS0hJnz57FjBkzMH78eEilUoXr5a9ldnY2Tp06hQ0bNiAgICDfOrOzs8WRYTltbW188skn4s///vuvUnvK97wCgMePHyuVYWpqCn19/aLcPhEREREREREREVGFo6enBz09vSJd8/fffyMuLk7hc3pLS0u8fv0az549U5gldP/+fVhaWop5Tp06pVCWfMLBu3nen4Rw//59GBsbw8DAoEhxckCoCIyNjXH06FEsXboUGRkZqFmzJhYtWoQOHTogOTkZ69atw7Rp05CZmQkrKyv4+/tj5syZGo3BwcEBEokEMpkMtWrVQvv27TFx4kSxcwBv1w8sqVjGjBmDxYsXY8GCBTh37hzWrFmjlMfExASenp4IDw8v1IBQfHw8GjdurJA2ePBgrF27Vimvjo4OwsLC0Lt37+LfhIb4+PjAzs4Oc+fOFZfNO3DgAKZNm4agoCA8fPgQdnZ2GD9+PCZOnKh0vYODA4C3Azo2NjYYPnw4QkND860zNjYW1apVUyrnypUr4s/fffcdvvvuO4U8GzZsQJs2bQBAab1JANi0aRN69epVqPsmIiIiIiIiIiIiKk0SrfK92FlkZCSqVKmi8Hm4q6srdHR0cOjQIXTv3h0AcPXqVaSmpqJly5YAgJYtW2Lu3Ll48OABqlSpAgA4ePAgjI2N4eTkJObZu3evQn0HDx4UyygKiSAIQrHukIj+k9p0PFLWIRAVi76eFuJi3AAAXgEJeJWdV8YRERUN+zB97NiH6WPHPkwVAfsxfezYh6miOParR1mH8NG5OyGo1OqyWrKpSPnz8vJgZ2eHoKAgfPvttwrnRo4cib179yIqKgrGxsYYO3YsACAxMREAkJubi0aNGsHKygoLFizAvXv30K9fPwwZMgTz5s0DANy6dQv169fH6NGjMWjQIPz+++8YN24c9uzZA29v7yLFyhlCRERERERERERERERUbkm0JGUdglpxcXFITU3FoEGDlM4tWbIEWlpa6N69O7Kzs+Ht7Y0VK1aI56VSKX777TeMHDkSLVu2hJGREfr37485c+aIeezs7LBnzx5MmDABy5YtQ/Xq1bF27doiDwYBHBAqNzp06ICEhASV56ZNm4Zp06aVckQfLjU1VZzWpsrly5dRo0aNEo9DJpOpPbdv3z64ubmVeAxEREREREREREREVPG0b98e6hZi09fXx48//ogff/xR7fU1a9ZUWhLufW3btsWff/75QXECHBAqN9auXYusrCyV58zMzEo5Gs2wsrJCcnJyvudLQ34xWFtbl0oMRERERERERERERFQ85X0PoY8FB4TKiYo4MKGtrQ17e/uyDqNcxEBEREREREREREREVJY4IEREREREREREREREROVWed5D6GPCeVZE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jJGRETw8PCCXyxu1IaRQKODq6qpSFxwcjO3bt9eJ1dbWRlRUFKZOndr8Sajx2WefoXfv3vjb3/6GzZs349GjR7Czs4OPjw8CAwMhl8vRrl07eHh41HnWw8MD+vr6+PLLL/Hee+8BAFauXCmst5mZGdzc3HDs2DHhU25PE4lE2Lt3L9avX49169Zh7ty50NPTw4ABA6BQKDBo0CCV+LKyMnTs2BEikQiGhobCZ/3ef/99lU2/uLg4rFixAnPnzsWNGzdgaWmJ//7v/xZyE4vF+Pe//40dO3bg7t27sLS0xKhRoxAVFQVdXV2NrC0RERERERERERERvbxEyiZcDKSlpYXr16/D3Nz8ReZERC+xweNOtHYK1AiWDp010o+7h2b62f33k8/dR5c3n32/VkN0tEXYvvLxpvpIn3RUVtX/SUVqfXyH6+I7/Gppi+8w8HzvMd9hetXp6Wohdd8QAHyH6dXF95hedXyHqa049c3Q1k7hlVN0pf570DXN1s6+xcZqaU26Q+ivcn8QERERERERERERERFRW9KkDaEmHCaienh5eUEqlaota9asae30mqW4uLjeOUmlUhQXF7dIHiEhIfXmEBIS0iI5EBEREREREREREZFmKSFqsdKWNekOoaKiIpiZmdWpr66uRmVlZZu/W0gTtm/fjoqKCrVtJiYmLZyNZlhaWiInJ6fB9pYQGRmJJUuWqG178r4dIiIiIiIiIiIiIqK/miZtCP373//Gd999hxkzZgh1q1evRlRUFKqrqzFixAjs2bMH7du313SebYaVlVVrp6BxEokE9vat/11Fc3Nz3m9F9L9++/FnjfSzW0P9aMLVnB+f63k9XS0AFppJhl44vsN18R1+tbTFdxh4vveY7zARERERETWXktfZaESTPhkXExODP//8U/g5MzMTK1euxIoVK7B371785z//QVRUlMaTJCIiIiIiIiIiIiIiouZr0gmhixcvYuDAgcLP+/btw1tvvYWPPvoIAKCnp4f3338fsbGxms2SiIiIiIiIiIiIiIj+kpRKnhDShCadELp37x5MTU2Fn0+dOgUPDw/hZxcXF/z222+ay46IiIiIiIiIiIiIiIieW5M2hKysrFBQUAAAuH//PnJzc1VODN26dQsGBgaazfAlVV5ejvDwcNjZ2UFPTw9mZmYYOnQoDh06hGvXrkEkEjVYEhMTG+xf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RERERERERERERPT84ISQBggEAgwYMADR0dE4efIkdHV18f/Yu/Popur8/+OvLF1JF7ZSCpXFQqFsMiIVEZCBobIIKDDIiCAIAoKKfAWmjIiAonYEqaiDSEthFDdEwQ0FpLJapVqWsslmVVpAlhYoBUvfvz/4NUNobtab5Ca8HufknEly+7mfXJ5jb3Nzcz/++GOryyYlJaG8vBxlZWUem8/FixexaNEidO7cGbVr11ZcTo25jB8/Hrt37za/3nfeeQf169fHjh07zGe05OXlYe7cucjKysKVK1dcXpc1JpMJ06dPx/PPP2/1+kjBwcFISEhAw4YNFc++ccTIkSORnZ2teHbQ/fffj/Pnz+PNN9+s8tzLL7+MoKAgDBgwwOLxRo0a4eabb0ZERITF4z169ECNGjXw0ksvuTTXhg0bIjw8HBcuXLD6/GOPPQa9Xo/09HS7Y6WmpqK4uNjiVj/hAZfmRUREREREREREROSKChGv3QKZ0dcT8Hc5OTlYv349evTogZiYGOTk5ODkyZNo3rw57rrrLgwZMgTt2rVDzZo1sWfPHkybNg1du3ZFZGSkanM4ceIEysrKcO7cOeTm5iItLQ1//PEHVq5caV7GU3MJDw/H6NGjMWPGDPTv3x8ZGRkYOHBglbNo4uPjkZqaijVr1qB37952xy0uLkZeXp7FYzVr1kR8fHyVZR955BG88sorWL58ufksG7WNHj0agwYNQnR0tNXnO3TogCeeeAKTJ0/G5cuX0b9/f/z55594++23kZ6ejvnz51uduzUmkwmLFy/G4MGD0bt3bzz++ONo0qQJzp8/jzVr1gC4emYaADz77LMoLS1Fr1690KBBA5w9exavvvoq/vzzT/ztb3+zOn5oaChmzpyJ8ePH251LSEgIQkJCLB7TG1w/sEZEREREREREREREvsEzhNwUGRmJjRs3olevXmjatCmefvppzJ07Fz179kRKSgqWLl2KHj16oHnz5njssceQkpKCDz74QNU5JCYmIi4uDrfeeitefPFFdO/eHbt370ZSUpJ5GU/OZcKECdi7dy/S0tKwY8eOKmfCAEBUVBS6deuGjIwMh8bMzs5G27ZtLW4zZ860umxQUBBmz57t0bOujEYjatWqZb4ukjXz58/HG2+8gXfffRctW7ZEu3btsHHjRnzyySd47LHHnFrfvffei61btyI8PBzDhg1DYmIi/vrXv+Kbb77Be++9hz59+gAAunTpgsOHD2PYsGFo1qwZevbsiaKiInz99ddITExUHH/48OFo3LixU3MiIiIiIiIiIiIiIv+lEwnwc6CISFV33vOtr6dADqhWI8rXU7Bw4XSx22OER7t3ZmVoiB6rF7cBAHQfuAlllwL8KoF+LqRamCrjXLpwUZVxtCA0RI91KzoBYMP+QG80qDJORbm6X7frS2yYtCDUVM31nw3R47OsvwBgw+Q7kbVruPXzIcE6fLzw6jd6sGPyhepxMW79fEiwDisWNAPAhsk33G240qdvNldlnBvJ/71h/fIYnjD3Udf3GbWOZwgREREREREREREREREFOB4Q0rCePXvCZDJZvc2ZM8fX03NJQUGB4msymUwoKCjwyjzGjh2rOIexY8d6ZQ5EREREREREREREZF9FhXjtFsiUL4hCPrd48WJcvGj9q25q1HDvNHFfiYuLQ15ens3nvWHWrFl46qmnrD4XGene11IREREREREREREREWkNDwhpWL169Xw9BdUZjUYkJCT4ehqIiYlBTIw63/lJRERERERERERERJ4jgX3ijtfwgBARUQC6cLrY11NQXenZErd+viKE35LqTy5dsH6GLJG/qCi/4uspEJEVZefduBjxn9yXIN8rOXnarZ8P5T4x+diZYyfc+vmrDTdTZzJELnC34f9prtI4RM7hASEiIiIiIiIiIiIiItIsCfBr+3gLPxpCREREREREREREREQU4HhASMNKS0uRmpqKm2++GaGhoahduza6dOmCVatW4ejRo9DpdDZvWVlZNsfPzs42L6vX6xEVFYW2bdtiypQpKCwsVH0u165Pp9Ohdu3a6NWrF3bt2mV1fikpKTAYDPjhhx+c2m4PPfSQeR1BQUFo1KgRpkyZgrKysirL/vbbbwgODkbLli2tjqXT6fDJJ58o3ndU5Ws/e/asxf0WLVrgyhXLr5SJjo62ur2s3bKzs5GVlWX1udDQUJe2CREREREREREREZGWVIh47RbI+JVxGjZ27Fjk5ORgwYIFSEpKwqlTp7B161acOnUK8fHxFgdtXn75ZaxZswbr1q0zPxYVFeXQevbv34/IyEiUlJTgxx9/RFpaGjIyMpCdnY1WrVqpNpecnByL9R07dgyTJ09G7969cfDgQQQHB5uXLygowNatWzFhwgRkZmbitttu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bZrFss8880yV+Y8ZMwajR492ex72ODNPT+revTuAqwfCGjRogK5du2LRokVISEiw+XMlJSVWvxqvsLDQohsiIiIiIiIiIiIiCiw6qbwSPRGRA+6851tfT4HIJaEheqxb0QkA0H3gJpRd4idLyL+wYfJ3bJj8HRumQMCOyd+xYQoUmz/t4usp+J17J/zstXV9/FoTr63L2/gdUURERERERERERERERAGOB4Q0qGfPnjCZTFZvc+bM8fX0XFJQUKD4mkwmEwoKCnw9RQD+M08iIiIiIiIiIiKiG4VUiNdugYzXENKgxYsX4+LFi1afq1Gjhpdno464uDjk5eXZfF4L/GWeRERERERERERERETO4AEhDapXr56vp6A6o9GIhIQEX0/DLn+ZJxERERGREr3RoMo4FeVXVBmHyFlsmIiIiMgzeECIiIiIiIiIiIiIiIg0SySwv8rNW3gNISIiIiIiIiIiIiIiogDHM4SIiIiIiIiIiIiIiEizKioqfD2FgMAzhHygtLQUqampuPnmmxEaGoratWujS5cuWLVqFY4ePQqdTmfzlpWVZXP87Oxs87J6vR5RUVFo27YtpkyZgsLCQtXncu36dDodateujV69emHXrl1W55eSkgKDwYAffvjBqe128uRJjBs3DjfddBNCQkIQGxuLlJQUbNmyxbxMw4YNrc7zxRdf9Po85s+fX+Vnn332Wdxyyy0271fO2Wg0omHDhnjyySdx/vx5AKjybxIREYEWLVpg/Pjx+Pnnny3WlZWVhejoaIv71rZNaGioU6+fiIiIiIiIiIiIiPwPzxDygbFjxyInJwcLFixAUlISTp06ha1bt+LUqVOIj4+3OGjz8ssvY82aNVi3bp35saioKIfWs3//fkRGRqKkpAQ//vgj0tLSkJGRgezsbLRq1Uq1ueTk5Fis79ixY5g8eTJ69+6NgwcPIjg42Lx8QUEBtm7digkTJiAzMxO33Xabw9ttwIABuHz5MpYuXYrGjRvj+PHjWL9+PU6dOmWx3KxZszB69GiLxyIiIizue2MermrRogXWrVuH8vJybNmyBSNHjkRpaSnefPNN8zLr1q1DixYtUFpail27diE9PR1t2rTBp59+im7duimOHRkZif3791s8ptPpVJk3ERERERERERERkSdIBa8hpAYeEPKgFStWYObMmTh48CDCw8PRtm1brFq1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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\n", + "# Make a single heatmap that includes all the years\n", + "# Create a df that contains the emissions of each ST for each year\n", + "# The rows are the sST and the columns are sES\n", + "# Each intersection should be divided in 7 columns, one for each year\n", + "# The value of each intersection should be the emissions of the ST for that year\n", + "# The heatmap should have a color scale that goes from 0 to the maximum value of the emissions\n", + "\n", + "# Create a df that contains the emissions of each ST for each year in the transport sector\n", + "emissions_2020_TRA = vEmiCO2ST_HEATMAP_2020_TRA.pivot(index='sST', columns='sES', values='vEmiCO2ST')\n", + "\n", + "\n", + "# Create a df that contains the emissions of each ST for each year\n", + "emissions_2025_TRA = vEmiCO2ST_HEATMAP_2025_TRA.pivot(index='sST', columns='sES', values='vEmiCO2ST')\n", + "\n", + "# Create a df that contains the emissions of each ST for each year\n", + "emissions_2030_TRA = vEmiCO2ST_HEATMAP_2030_TRA.pivot(index='sST', columns='sES', values='vEmiCO2ST')\n", + "\n", + "# Create a df that contains the emissions of each ST for each year\n", + "emissions_2035_TRA = vEmiCO2ST_HEATMAP_2035_TRA.pivot(index='sST', columns='sES', values='vEmiCO2ST')\n", + "\n", + "# Create a df that contains the emissions of each ST for each year\n", + "emissions_2040_TRA = vEmiCO2ST_HEATMAP_2040_TRA.pivot(index='sST', columns='sES', values='vEmiCO2ST')\n", + "\n", + "# Create a df that contains the emissions of each ST for each year\n", + "emissions_2045_TRA = vEmiCO2ST_HEATMAP_2045_TRA.pivot(index='sST', columns='sES', values='vEmiCO2ST')\n", + "\n", + "# Create a df that contains the emissions of each ST for each year\n", + "emissions_2050_TRA = vEmiCO2ST_HEATMAP_2050_TRA.pivot(index='sST', columns='sES', values='vEmiCO2ST')\n", + "\n", + "# Create a df that contains the emissions of each ST for each year\n", + "emissions = pd.concat([emissions_2020_TRA, emissions_2025_TRA, emissions_2030_TRA, emissions_2035_TRA, emissions_2040_TRA, emissions_2045_TRA, emissions_2050_TRA], axis=1)\n", + "\n", + "# replace NaN values with 0\n", + "emissions.fillna(0, inplace=True)\n", + "\n", + "# Increase the size of the plot in sucha way that all the years are visible an sST and sES are readable\n", + "plt.figure(figsize=(20, 7))\n", + "# Create a heatmap\n", + "sns.heatmap(emissions, cmap='coolwarm',vmin=0, vmax=emissions.max().max())\n", + "#Insert a separator between the years\n", + "plt.axvline(x=[10], color='white')\n", + "plt.axvline(x=[20], color='white')\n", + "plt.axvline(x=[30], color='white')\n", + "plt.axvline(x=[40], color='white')\n", + "plt.axvline(x=[50], color='white')\n", + "plt.axvline(x=[60], color='white')\n", + "\n", + "# Add a label to each axvline\n", + "plt.text(4, -0.5, '2020', fontsize=12, color='black')\n", + "plt.text(14, -0.5, '2025', fontsize=12, color='black')\n", + "plt.text(24, -0.5, '2030', fontsize=12, color='black')\n", + "plt.text(34, -0.5, '2035', fontsize=12, color='black')\n", + "plt.text(44, -0.5, '2040', fontsize=12, color='black')\n", + "plt.text(54, -0.5, '2045', fontsize=12, color='black')\n", + "plt.text(64, -0.5, '2050', fontsize=12, color='black')\n", + "\n", + "# Rotate the x axis labels\n", + "plt.title('CO2 emissions of each STTra (vQSTInTE + vQSTOut) to sES for each year [MtCO2]', y=1.05)\n", + "#move the title more to the top\n", + "plt.xlabel('sES')\n", + "plt.ylabel('sST')\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Graph total STTra CO2 emissions for each year\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "emissions = [TotEmiSTTra_2020, TotEmiSTTra_2025, TotEmiSTTra_2030, TotEmiSTTra_2035, TotEmiSTTra_2040, TotEmiSTTra_2045, TotEmiSTTra_2050]\n", + "cap = data_input['pEmiCO2CapTra']\n", + "\n", + "plt.plot(years, emissions, marker='o')\n", + "plt.plot(years, cap.pEmiCO2CapTra, marker='o')\n", + "plt.title('Total CO2 emissions of the Transport Sector for each year [MtCO2]')\n", + "plt.legend(['Total CO2 emissions', 'CO2 Cap'])\n", + "plt.xlabel('Year')\n", + "plt.ylabel('[MtCO2]')\n", + "plt.show()\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'vEmiCO2ST_HEATMAP_2020_IND' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[49], line 10\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;66;03m# Make a single heatmap that includes all the years\u001b[39;00m\n\u001b[0;32m 2\u001b[0m \u001b[38;5;66;03m# Create a df that contains the emissions of each ST for each year\u001b[39;00m\n\u001b[0;32m 3\u001b[0m \u001b[38;5;66;03m# The rows are the sST and the columns are sES\u001b[39;00m\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 7\u001b[0m \n\u001b[0;32m 8\u001b[0m \u001b[38;5;66;03m# Create a df that contains the emissions of each ST for each year in the industrial sector\u001b[39;00m\n\u001b[1;32m---> 10\u001b[0m emissions_2020_IND \u001b[38;5;241m=\u001b[39m \u001b[43mvEmiCO2ST_HEATMAP_2020_IND\u001b[49m\u001b[38;5;241m.\u001b[39mpivot(index\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msST\u001b[39m\u001b[38;5;124m'\u001b[39m, columns\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msES\u001b[39m\u001b[38;5;124m'\u001b[39m, values\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mvEmiCO2ST\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[0;32m 11\u001b[0m emissions_2025_IND \u001b[38;5;241m=\u001b[39m vEmiCO2ST_HEATMAP_2025_IND\u001b[38;5;241m.\u001b[39mpivot(index\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msST\u001b[39m\u001b[38;5;124m'\u001b[39m, columns\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msES\u001b[39m\u001b[38;5;124m'\u001b[39m, values\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mvEmiCO2ST\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[0;32m 12\u001b[0m emissions_2030_IND \u001b[38;5;241m=\u001b[39m vEmiCO2ST_HEATMAP_2030_IND\u001b[38;5;241m.\u001b[39mpivot(index\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msST\u001b[39m\u001b[38;5;124m'\u001b[39m, columns\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msES\u001b[39m\u001b[38;5;124m'\u001b[39m, values\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mvEmiCO2ST\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", + "\u001b[1;31mNameError\u001b[0m: name 'vEmiCO2ST_HEATMAP_2020_IND' is not defined" + ] + } + ], + "source": [ + "# Make a single heatmap that includes all the years\n", + "# Create a df that contains the emissions of each ST for each year\n", + "# The rows are the sST and the columns are sES\n", + "# Each intersection should be divided in 7 columns, one for each year\n", + "# The value of each intersection should be the emissions of the ST for that year\n", + "# The heatmap should have a color scale that goes from 0 to the maximum value of the emissions\n", + "\n", + "# Create a df that contains the emissions of each ST for each year in the industrial sector\n", + "\n", + "emissions_2020_IND = vEmiCO2ST_HEATMAP_2020_IND.pivot(index='sST', columns='sES', values='vEmiCO2ST')\n", + "emissions_2025_IND = vEmiCO2ST_HEATMAP_2025_IND.pivot(index='sST', columns='sES', values='vEmiCO2ST')\n", + "emissions_2030_IND = vEmiCO2ST_HEATMAP_2030_IND.pivot(index='sST', columns='sES', values='vEmiCO2ST')\n", + "emissions_2035_IND = vEmiCO2ST_HEATMAP_2035_IND.pivot(index='sST', columns='sES', values='vEmiCO2ST')\n", + "emissions_2040_IND = vEmiCO2ST_HEATMAP_2040_IND.pivot(index='sST', columns='sES', values='vEmiCO2ST')\n", + "emissions_2045_IND = vEmiCO2ST_HEATMAP_2045_IND.pivot(index='sST', columns='sES', values='vEmiCO2ST')\n", + "emissions_2050_IND = vEmiCO2ST_HEATMAP_2050_IND.pivot(index='sST', columns='sES', values='vEmiCO2ST')\n", + "\n", + "# Create a df that contains the emissions of each ST for each year\n", + "emissions_IND = pd.concat([emissions_2020_IND, emissions_2025_IND, emissions_2030_IND, emissions_2035_IND, emissions_2040_IND, emissions_2045_IND, emissions_2050_IND], axis=1)\n", + "\n", + "# replace NaN values with 0\n", + "emissions_IND.fillna(0, inplace=True)\n", + "\n", + "# Increase the size of the plot in sucha way that all the years are visible an sST and sES are readable\n", + "plt.figure(figsize=(25, 3))\n", + "# Create a heatmap\n", + "sns.heatmap(emissions_IND, cmap='coolwarm',vmin=0, vmax=emissions_IND.max().max())\n", + "#Insert a separator between the years\n", + "plt.axvline(x=[13], color='white')\n", + "plt.axvline(x=[26], color='white')\n", + "plt.axvline(x=[39], color='white')\n", + "plt.axvline(x=[52], color='white')\n", + "plt.axvline(x=[65], color='white')\n", + "plt.axvline(x=[78], color='white')\n", + "\n", + "\n", + "# Add a label to each axvline\n", + "plt.text(6, -0.5, '2020', fontsize=12, color='black')\n", + "plt.text(18, -0.5, '2025', fontsize=12, color='black')\n", + "plt.text(30, -0.5, '2030', fontsize=12, color='black')\n", + "plt.text(42, -0.5, '2035', fontsize=12, color='black')\n", + "plt.text(54, -0.5, '2040', fontsize=12, color='black')\n", + "plt.text(66, -0.5, '2045', fontsize=12, color='black')\n", + "plt.text(78, -0.5, '2050', fontsize=12, color='black')\n", + "\n", + "# Rotate the x axis labels\n", + "plt.title('CO2 emissions of each STInd (vQSTInTE + vQSTOut) for each year [MtCO2]', y=1.07)\n", + "#move the title more to the top\n", + "plt.xlabel('sES')\n", + "plt.ylabel('sST')\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'TotEmiSTInd_2020_PRO' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[48], line 3\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;66;03m#Graph total STTra CO2 emissions for each year\u001b[39;00m\n\u001b[0;32m 2\u001b[0m years \u001b[38;5;241m=\u001b[39m [\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m2020\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m2025\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m2030\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m2035\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m2040\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m2045\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m2050\u001b[39m\u001b[38;5;124m'\u001b[39m]\n\u001b[1;32m----> 3\u001b[0m emissions_Pro \u001b[38;5;241m=\u001b[39m [\u001b[43mTotEmiSTInd_2020_PRO\u001b[49m, TotEmiSTInd_2025_PRO, TotEmiSTInd_2030_PRO, TotEmiSTInd_2035_PRO, TotEmiSTInd_2040_PRO, TotEmiSTInd_2045_PRO, TotEmiSTInd_2050_PRO]\n\u001b[0;32m 4\u001b[0m emissions_TE \u001b[38;5;241m=\u001b[39m [TotEmiSTInd_2020_TE, TotEmiSTInd_2025_TE, TotEmiSTInd_2030_TE, TotEmiSTInd_2035_TE, TotEmiSTInd_2040_TE, TotEmiSTInd_2045_TE, TotEmiSTInd_2050_TE] \n\u001b[0;32m 5\u001b[0m cap_pro \u001b[38;5;241m=\u001b[39m data_input[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mpEmiCO2CapIndPro\u001b[39m\u001b[38;5;124m'\u001b[39m]\n", + "\u001b[1;31mNameError\u001b[0m: name 'TotEmiSTInd_2020_PRO' is not defined" + ] + } + ], + "source": [ + "#Graph total STTra CO2 emissions for each year\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "emissions_Pro = [TotEmiSTInd_2020_PRO, TotEmiSTInd_2025_PRO, TotEmiSTInd_2030_PRO, TotEmiSTInd_2035_PRO, TotEmiSTInd_2040_PRO, TotEmiSTInd_2045_PRO, TotEmiSTInd_2050_PRO]\n", + "emissions_TE = [TotEmiSTInd_2020_TE, TotEmiSTInd_2025_TE, TotEmiSTInd_2030_TE, TotEmiSTInd_2035_TE, TotEmiSTInd_2040_TE, TotEmiSTInd_2045_TE, TotEmiSTInd_2050_TE] \n", + "cap_pro = data_input['pEmiCO2CapIndPro']\n", + "cap_te = data_input['pEmiCO2CapIndTE']\n", + "\n", + "plt.plot(years, emissions_Pro, marker='o',color='red')\n", + "plt.plot(years, emissions_TE, marker='o',color='b')\n", + "plt.plot(years, cap_te.pEmiCO2CapIndTE, marker='o',linestyle='dashed',color='b')\n", + "plt.plot(years, cap_pro.pEmiCO2CapIndPro, marker='o',linestyle='dashed',color='r')\n", + "plt.title('Total CO2 emissions of the Transport Sector for each year [MtCO2]')\n", + "plt.legend(['Total CO2 emissions Pro', 'Total CO2 emissions TE', 'CO2 Cap TE', 'CO2 Cap Pro'])\n", + "plt.xlabel('Year')\n", + "plt.ylabel('[MtCO2]')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "Total_CO2_Emmisions = data_results['vEmiCO2Tot']\n", + "CapTotal = data_input['pEmiCO2Cap']\n", + "\n", + "plt.plot(Total_CO2_Emmisions['sYear'], Total_CO2_Emmisions['vEmiCO2Tot'])\n", + "plt.plot(CapTotal['sYear'], CapTotal['pEmiCO2Cap'])\n", + "plt.title('Total CO2 emissions')\n", + "plt.legend(['Total CO2 emissions', 'CO2 Cap'])\n", + "plt.xlabel('Year')\n", + "plt.ylabel('[MtCO2]')\n", + "plt.grid()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "NOX" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sCEsYearvCECapExc
252sPE2TE_IMCOy2020848.1
253sPE2TE_IMCOy2025798.2
254sPE2TE_IMCOy2030748.3
255sPE2TE_IMCOy2035698.4
256sPE2TE_IMCOy2040648.5
257sPE2TE_IMCOy2045598.6
258sPE2TE_IMCOy2050548.7
259sPE2TE_NAGASy2020848.1
260sPE2TE_NAGASy2025798.2
261sPE2TE_NAGASy2030748.3
262sPE2TE_NAGASy2035698.4
263sPE2TE_NAGASy2040648.5
264sPE2TE_NAGASy2045598.6
265sPE2TE_NAGASy2050548.7
266sPE2TE_BIOMAy2020848.1
267sPE2TE_BIOMAy2025798.2
268sPE2TE_BIOMAy2030748.3
269sPE2TE_BIOMAy2035698.4
270sPE2TE_BIOMAy2040648.5
271sPE2TE_BIOMAy2045598.6
272sPE2TE_BIOMAy2050548.7
273sTE2TE_TEELEINDy2020848.1
274sTE2TE_TEELEINDy2025798.2
275sTE2TE_TEELEINDy2030748.3
276sTE2TE_TEELEINDy2035698.4
277sTE2TE_TEELEINDy2040648.5
278sTE2TE_TEELEINDy2045598.6
279sTE2TE_TEELEINDy2050548.7
280sTE2TE_TEELEOTHy2020848.1
281sTE2TE_TEELEOTHy2025798.2
282sTE2TE_TEELEOTHy2030748.3
283sTE2TE_TEELEOTHy2035698.4
284sTE2TE_TEELEOTHy2040648.5
285sTE2TE_TEELEOTHy2045598.6
286sTE2TE_TEELEOTHy2050548.7
287sTE2TE_TEELETRAy2020848.1
288sTE2TE_TEELETRAy2025798.2
289sTE2TE_TEELETRAy2030748.3
290sTE2TE_TEELETRAy2035698.4
291sTE2TE_TEELETRAy2040648.5
292sTE2TE_TEELETRAy2045598.6
293sTE2TE_TEELETRAy2050548.7
\n", + "
" + ], + "text/plain": [ + " sCE sYear vCECapExc\n", + "252 sPE2TE_IMCO y2020 848.1\n", + "253 sPE2TE_IMCO y2025 798.2\n", + "254 sPE2TE_IMCO y2030 748.3\n", + "255 sPE2TE_IMCO y2035 698.4\n", + "256 sPE2TE_IMCO y2040 648.5\n", + "257 sPE2TE_IMCO y2045 598.6\n", + "258 sPE2TE_IMCO y2050 548.7\n", + "259 sPE2TE_NAGAS y2020 848.1\n", + "260 sPE2TE_NAGAS y2025 798.2\n", + "261 sPE2TE_NAGAS y2030 748.3\n", + "262 sPE2TE_NAGAS y2035 698.4\n", + "263 sPE2TE_NAGAS y2040 648.5\n", + "264 sPE2TE_NAGAS y2045 598.6\n", + "265 sPE2TE_NAGAS y2050 548.7\n", + "266 sPE2TE_BIOMA y2020 848.1\n", + "267 sPE2TE_BIOMA y2025 798.2\n", + "268 sPE2TE_BIOMA y2030 748.3\n", + "269 sPE2TE_BIOMA y2035 698.4\n", + "270 sPE2TE_BIOMA y2040 648.5\n", + "271 sPE2TE_BIOMA y2045 598.6\n", + "272 sPE2TE_BIOMA y2050 548.7\n", + "273 sTE2TE_TEELEIND y2020 848.1\n", + "274 sTE2TE_TEELEIND y2025 798.2\n", + "275 sTE2TE_TEELEIND y2030 748.3\n", + "276 sTE2TE_TEELEIND y2035 698.4\n", + "277 sTE2TE_TEELEIND y2040 648.5\n", + "278 sTE2TE_TEELEIND y2045 598.6\n", + "279 sTE2TE_TEELEIND y2050 548.7\n", + "280 sTE2TE_TEELEOTH y2020 848.1\n", + "281 sTE2TE_TEELEOTH y2025 798.2\n", + "282 sTE2TE_TEELEOTH y2030 748.3\n", + "283 sTE2TE_TEELEOTH y2035 698.4\n", + "284 sTE2TE_TEELEOTH y2040 648.5\n", + "285 sTE2TE_TEELEOTH y2045 598.6\n", + "286 sTE2TE_TEELEOTH y2050 548.7\n", + "287 sTE2TE_TEELETRA y2020 848.1\n", + "288 sTE2TE_TEELETRA y2025 798.2\n", + "289 sTE2TE_TEELETRA y2030 748.3\n", + "290 sTE2TE_TEELETRA y2035 698.4\n", + "291 sTE2TE_TEELETRA y2040 648.5\n", + "292 sTE2TE_TEELETRA y2045 598.6\n", + "293 sTE2TE_TEELETRA y2050 548.7" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data_results['vCECapExc'][data_results['vCECapExc'].vCECapExc!=0]" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sSTsYearvSTCapExc
98sST_DSTRA_LNP_BUSELEy20201.117219
126sST_DSTRA_RAIL_URBANy20208.535912
127sST_DSTRA_RAIL_URBANy20250.246661
128sST_DSTRA_RAIL_URBANy20301.857882
129sST_DSTRA_RAIL_URBANy20352.745627
130sST_DSTRA_RAIL_URBANy20402.266191
131sST_DSTRA_RAIL_URBANy20451.593680
132sST_DSTRA_RAIL_URBANy20501.601019
202sST_DSTRA_LNF_TRUBIELEy20500.530193
329sST_DSOTH_RESFRID_HEFFy202051.142432
330sST_DSOTH_RESFRID_HEFFy20252.078203
331sST_DSOTH_RESFRID_HEFFy20309.184486
\n", + "
" + ], + "text/plain": [ + " sST sYear vSTCapExc\n", + "98 sST_DSTRA_LNP_BUSELE y2020 1.117219\n", + "126 sST_DSTRA_RAIL_URBAN y2020 8.535912\n", + "127 sST_DSTRA_RAIL_URBAN y2025 0.246661\n", + "128 sST_DSTRA_RAIL_URBAN y2030 1.857882\n", + "129 sST_DSTRA_RAIL_URBAN y2035 2.745627\n", + "130 sST_DSTRA_RAIL_URBAN y2040 2.266191\n", + "131 sST_DSTRA_RAIL_URBAN y2045 1.593680\n", + "132 sST_DSTRA_RAIL_URBAN y2050 1.601019\n", + "202 sST_DSTRA_LNF_TRUBIELE y2050 0.530193\n", + "329 sST_DSOTH_RESFRID_HEFF y2020 51.142432\n", + "330 sST_DSOTH_RESFRID_HEFF y2025 2.078203\n", + "331 sST_DSOTH_RESFRID_HEFF y2030 9.184486" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# SEE THE VALUES OF data_results['vSTCapExc'] DIFFERENT FROM ZERO\n", + "\n", + "data_results['vSTCapExc'][data_results['vSTCapExc'].vSTCapExc!=0]" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "openMaster_H2Included", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/notebooks/Results_FastAnalysis_.ipynb b/notebooks/Results_FastAnalysis_.ipynb new file mode 100644 index 0000000..e69de29 diff --git a/notebooks/correlation_openMASTER.ipynb b/notebooks/correlation_openMASTER.ipynb new file mode 100644 index 0000000..2e1ec12 --- /dev/null +++ b/notebooks/correlation_openMASTER.ipynb @@ -0,0 +1,516 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# OpenMASTER - correlations" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "-------------------------" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import pyomo.environ as pyo\n", + "import openMASTER\n", + "import numpy as np\n", + "import itertools\n", + "import pandas as pd" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Define the abstract model" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m = openMASTER.make_model()\n", + "m" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Model data upload\n", + "\n", + "* If you haven't created the .csv files, please:\n", + " * Be aware the openMASTER_Data.xlsx file has to be downloaded using git-lfs or the following link:\n", + " https://github.com/IIT-EnergySystemModels/openMASTER/raw/main/data/input/openMASTER_Data.xlsx?download=\n", + " * Run the first line of code in this cell, which will both create the .csv files and load them into the DataPortal (this whole function takes several minutes)\n", + "\n", + "* On the contrary, if you have already created the .csv files from the Excel file and haven't changed them, you can directly go on to the second line of code. This will save some minutes.\n", + "\n", + "In any case, add \"#\" in front of the line you are not running." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "data = openMASTER.load_dataportal_from_excel('../data/input/openMASTER_Data.xlsx')\n", + "#data = openMASTER.load_dataportal_from_csv()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Principal components analysis (PCA)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "'''\n", + "# Leer datos históricos\n", + "csv_data = '..\\data\\input\\covar.xlsx'\n", + "sheet_name = 'data'\n", + "df_data = pd.read_excel(csv_data, sheet_name=sheet_name, header=[0])\n", + "X_hist = df_data.values\n", + "\n", + "# Leer datos históricos\n", + "csv_data = '..\\data\\input\\covar.xlsx'\n", + "sheet_name = 'covar_zscore_orig'\n", + "df_covar = pd.read_excel(csv_data, sheet_name=sheet_name, header=[0], index_col=0)\n", + "X_covar = df_covar.values\n", + "\n", + "# Calcular la media y la desviación estándar de X_hist\n", + "X_mean_hist = np.mean(X_hist, axis=0)\n", + "X_std_hist = np.std(X_hist, axis=0)\n", + "\n", + "# Normalizar X_hist con z-score\n", + "X_hist_normalized = np.nan_to_num((X_hist - X_mean_hist) / X_std_hist)\n", + "\n", + "# Calcular la matriz de covarianza de X_hist normalizada\n", + "X_covar_normalized = np.cov(X_hist_normalized, rowvar=False)\n", + "\n", + "\n", + "# Identificar las posiciones de las filas y columnas específicas\n", + "column_positions = [1, 2, 3, 4]\n", + "row_positions = [31, 32, 33, 34, 35, 36, 37, 38, 39, 40]\n", + "\n", + "# Cambiar los valores en la matriz X_covar_normalized para las combinaciones específicas (filas y columnas)\n", + "#for row_pos in row_positions:\n", + "# for col_pos in column_positions:\n", + "# X_covar_normalized[row_pos, col_pos] = 0.5 # Cambia aquí el valor deseado\n", + "# X_covar_normalized[col_pos, row_pos] = 0.5 # Asegura la simetría\n", + "\n", + "# Asegurarse de que las desviaciones estándar no sean cero\n", + "X_std_hist[X_std_hist == 0] = 1 # Establecer cualquier desviación estándar igual a cero en 1\n", + "\n", + "import numpy as np\n", + "\n", + "# Verificar si la matriz es simétrica\n", + "def is_symmetric(matrix):\n", + " return np.allclose(matrix, matrix.T)\n", + "\n", + "# Verificar si todos los autovalores son positivos\n", + "def is_positive_definite(matrix):\n", + " eigenvalues = np.linalg.eigvalsh(matrix)\n", + " return np.all(eigenvalues > 0)\n", + "\n", + "# Verificar si la matriz es positiva definida\n", + "def is_pos_def(matrix):\n", + " return is_symmetric(matrix) and is_positive_definite(matrix)\n", + "\n", + "# Ejemplo de uso:\n", + "is_pos_def(X_covar)\n", + "\n", + "# Calcula la descomposición de Cholesky de la matriz de covarianza normalizada\n", + "#L_normalized = np.linalg.cholesky(X_covar_normalized)\n", + "\n", + "# Escala los elementos diagonales de L por las desviaciones estándar originales\n", + "#L_scaled = np.dot(np.diag(X_std_hist), L_normalized)\n", + "\n", + "# Calcula la matriz de covarianza escalada\n", + "#X_covar_scaled = np.dot(L_scaled, L_scaled.T)\n", + "'''" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "csv_mean = '..\\data\\input\\mean.csv'\n", + "df_mean = pd.read_csv(csv_mean, delimiter=';', header=[0])\n", + "X_mean = df_mean.values\n", + "\n", + "\n", + "csv_covar = '..\\data\\input\\covar.xlsx'\n", + "#sheet_name = 'covar_zscore'\n", + "sheet_name = 'covar'\n", + "df_covar = pd.read_excel(csv_covar, sheet_name=sheet_name, index_col=0)\n", + "X_covar = df_covar.values\n", + "\n", + "\n", + "csv_data = '..\\data\\input\\covar.xlsx'\n", + "sheet_name = 'data'\n", + "df_data = pd.read_excel(csv_data, sheet_name=sheet_name, header=[0])\n", + "X_hist = df_data.values\n", + "X = X_hist \n", + "\n", + "f_set = data['f']\n", + "unc_set = data['sUnc']\n", + "\n", + "\n", + "# Set a seed for reproducibility\n", + "np.random.seed(93) # You can use any integer value as the seed\n", + "\n", + "# Calcula la desviación estándar de X_hist\n", + "#X_std_hist = np.std(X_hist, axis=0)\n", + "\n", + "\n", + "# Generar datos sintéticos siguiendo una distribución normal estándar\n", + "#X_adjusted= np.random.multivariate_normal(np.ravel(X_mean), X_covar, size=10000)\n", + "\n", + "# Escalar para ajustar la varianza utilizando la desviación estándar de X_hist\n", + "#X_scaled = X_std * X_std_hist\n", + "\n", + "# Aplicar transformación lineal para ajustar las medias\n", + "#X_adjusted = X_scaled + X_mean\n", + "\n", + "# Definir los valores mínimos y máximos de los parámetros\n", + "#min_values = np.min(X_hist, axis=0)\n", + "#max_values = np.max(X_hist, axis=0)\n", + "\n", + "# Ajustar para que los datos estén dentro de los rangos mínimo y máximo\n", + "#X_bounded = np.clip(X_adjusted, min_values, max_values)\n", + "\n", + "# Ensure all values are non-negative\n", + "#X = np.maximum(X_adjusted, 0)\n", + "\n", + "#X_o = X - np.mean(X, axis=0)\n", + "\n", + "'''\n", + "# Calcula la desviación estándar de X_hist\n", + "X_std_hist = np.std(X_hist, axis=0)\n", + "\n", + "# Calcular el factor de escalado necesario para garantizar que ningún valor sea inferior al mínimo de la serie histórica\n", + "min_values_hist = np.min(X_hist, axis=0)\n", + "min_values_scaled = np.min(X_mean, axis=0)\n", + "scaling_factor = (min_values_scaled - min_values_hist) / X_std_hist\n", + "\n", + "# Generar datos sintéticos siguiendo una distribución normal estándar, escalados según el factor calculado\n", + "X_std = np.random.multivariate_normal(np.zeros(len(np.ravel(X_mean))), X_covar, size=10000)\n", + "X_scaled = X_std * scaling_factor\n", + "\n", + "# Aplicar transformación lineal para ajustar las medias\n", + "X_adjusted = X_scaled + X_mean\n", + "\n", + "X = np.nan_to_num(X_adjusted)\n", + "'''\n", + "\n", + "# Calcular las varianzas de la serie histórica\n", + "variances_hist = np.var(X_hist, axis=0)\n", + "\n", + "# Crear una matriz diagonal a partir de las varianzas de X_hist\n", + "variances_diag = np.diag(variances_hist)\n", + "\n", + "# Escalar la matriz de covarianza utilizando la matriz diagonal de varianzas\n", + "scaling_factor = 0.08\n", + "scaled_covar = np.dot(X_covar, variances_diag) * scaling_factor\n", + "\n", + "# Generar los datos sintéticos utilizando la media y la matriz de covarianza escalada\n", + "X = np.random.multivariate_normal(np.ravel(X_mean), scaled_covar, size=10000)\n", + "\n", + "X_o = X - np.mean(X, axis=0)\n", + "\n", + "s_bar_dict = {unc: np.ravel(X_mean)[i] for i, unc in enumerate(unc_set)}\n", + "\n", + "\n", + "from sklearn.decomposition import PCA\n", + "#we compute the singular value decomposition\n", + "\n", + "#we use eigvals, eigvecs so they are not ordered in decreasing order\n", + "#eigvals, eigvecs = np.linalg.eig(np.cov(X_o.T))\n", + "\n", + "#eigvecs_real = np.real(eigvecs)\n", + "#eigvecs_imag = np.imag(eigvecs)\n", + "\n", + "#eigvals_real = np.real(eigvals)\n", + "#eigvals_imag = np.imag(eigvals)\n", + "\n", + "cov_matrix = np.cov(X_o.T)\n", + "\n", + "\n", + "u, s, vh = np.linalg.svd(cov_matrix, full_matrices=True)\n", + "#u, s, vh = np.linalg.svd(X_covar, full_matrices=True)\n", + "\n", + "#pca1 = PCA()\n", + "#pca1.fit(X_o)\n", + "\n", + "#u2, s2, vh2 = np.linalg.svd(np.cov(X_z_clean.T), full_matrices=True)\n", + "#pca2 = PCA()\n", + "#pca2.fit(X_z_clean)\n", + "\n", + "# Comparar los componentes principales obtenidos de ambos métodos\n", + "#print(\"Componentes principales obtenidos por el método 1:\")\n", + "#print(pca1.components_)\n", + "#print(\"\\nComponentes principales obtenidos por el método 2:\")\n", + "#print(pca2.components_)\n", + "\n", + "# Comprobación de similitud\n", + "#similarity = np.allclose(pca1.components_, pca2.components_)\n", + "#print(\"\\n¿Los componentes principales son similares?\", similarity)\n", + "\n", + "\n", + "##np.linalg.svd --> Singular Value Decomposition:\n", + "##np.cov --> estimate the covariance matrix\n", + "##u is eigenvector matrix and s are the eigenvalues\n", + "\n", + "#prueba = np.dot(X_o, u)\n", + "\n", + "#now we compute the vectors needed to build the uncertainty region\n", + "w_max = np.max(np.dot(X_o, u) / np.linalg.norm(u, axis=0), 0)\n", + "#w_max = np.where((w_max > -1e-03) & (w_max < 1e-03), 0, w_max)\n", + "w_max_dict = {f_i: w_max[i] for i, f_i in enumerate(f_set)}\n", + "#w_max_dict = {f_i: w_max[i-1] for i, f_i in enumerate(f_set)}\n", + "\n", + "w_min = np.min(np.dot(X_o, u) / np.linalg.norm(u, axis=0), 0)\n", + "#w_min = np.where((w_min > -1e-03) & (w_min < 1e-03), 0, w_min)\n", + "w_min_dict = {f_i: w_min[i] for i, f_i in enumerate(f_set)}\n", + "#w_min_dict = {f_i: w_min[i-1] for i, f_i in enumerate(f_set)}\n", + "\n", + "alpha_up = (w_max / np.linalg.norm(u, axis=0)) * u\n", + "alpha_up_dict = {(unc, f_i): alpha_up[i, j] for i, unc in enumerate(unc_set) for j, f_i in enumerate(f_set)}\n", + "\n", + "alpha_do = (w_min / np.linalg.norm(u, axis=0)) * u\n", + "alpha_do_dict = {(unc, f_i): alpha_do[i, j] for i, unc in enumerate(unc_set) for j, f_i in enumerate(f_set)}\n", + "\n", + "rest = ((w_max + w_min) / (2 * np.linalg.norm(u, axis=0))) * u\n", + "rest_dict = {(unc, f_i): rest[i, j] for i, unc in enumerate(unc_set) for j, f_i in enumerate(f_set)}\n", + "\n", + "\n", + "data._data[None][m.pS.name] = s_bar_dict\n", + "data._data[None][m.pW_max.name] = w_max_dict\n", + "data._data[None][m.pW_min.name] = w_min_dict\n", + "data._data[None][m.pAlpha_up.name] = alpha_up_dict\n", + "data._data[None][m.pAlpha_do.name] = alpha_do_dict\n", + "data._data[None][m.pRest.name] = rest_dict\n", + "\n", + "print(alpha_up_dict)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Create the instance of the abstract model " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "instance = m.create_instance(data)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#instance.write('instance.lp', io_options={'symbolic_solver_labels': True})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#data._data[None][m.pCECapex.name]\n", + "#instance.pS.pprint()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solve the model instance\n", + "\n", + "To solve the model instance, please select a solver within the Pyomo SolverFactory. Please note that any solver has to be previously installed." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "solver = pyo.SolverFactory('gurobi')\n", + "\n", + "solver_results = solver.solve(instance, keepfiles=False, tee=True)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### **Results**" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Extract information on variables through the model output to .csv files" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "path = \"../data/input/openMASTER_Data.xlsx\"\n", + "output_path = \"../data/tmp/output\"\n", + "sheetname = \"Output\"\n", + "\n", + "d_vars_from_instance = openMASTER.export_model_to_csv(path, output_path, sheetname, instance)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Loading variable information from .csv to a dictionary containing all outputs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "d_vars = openMASTER.import_results_from_csv(output_path)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "\n", + "vQSTInTE_results = d_vars['vQSTInTE']\n", + "vQSTInTE_sum = vQSTInTE_results.groupby(['sYear', 'sTE', 'sST']).sum()\n", + "\n", + "# Define the output file path\n", + "output_file = os.path.join(output_path, \"vQSTInTE_sum.csv\")\n", + "\n", + "# Save the DataFrame as a CSV file\n", + "vQSTInTE_sum.to_csv(output_file)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Checks" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "vQESNS_results = d_vars['vQESNS']\n", + "vQESNS_sum = vQESNS_results['vQESNS'].sum()\n", + "print(\"Sum of vQESNS: \", vQESNS_sum)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "vEmiCO2CapTraExc_sum = d_vars['vEmiCO2CapTraExc'].sum()\n", + "vEmiCO2CapEleExc_sum = d_vars['vEmiCO2CapEleExc'].sum()\n", + "vEmiCO2CapIndTEExc_sum = d_vars['vEmiCO2CapIndTEExc'].sum()\n", + "vEmiCO2CapIndProExc_sum = d_vars['vEmiCO2CapIndProExc'].sum()\n", + "vEmiCO2CapOthExc_sum = d_vars['vEmiCO2CapOthExc'].sum()\n", + "vEmiCO2CapRefExc_sum = d_vars['vEmiCO2CapRefExc'].sum()\n", + "\n", + "print(\"Sum of vEmiCO2CapTraExc: \", vEmiCO2CapTraExc_sum)\n", + "print(\"Sum of vEmiCO2CapEleExc: \", vEmiCO2CapEleExc_sum)\n", + "print(\"Sum of vEmiCO2CapIndTEExc: \", vEmiCO2CapIndTEExc_sum)\n", + "print(\"Sum of vEmiCO2CapIndProExc: \", vEmiCO2CapIndProExc_sum)\n", + "print(\"Sum of vEmiCO2CapOthExc: \", vEmiCO2CapOthExc_sum)\n", + "print(\"Sum of vEmiCO2CapRefExc: \", vEmiCO2CapRefExc_sum)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.11" + }, + "vscode": { + "interpreter": { + "hash": "b0517a97abf0a6b47b3d9f8b7b88c86ebe679f61210aefcb79cf5ebc38f36513" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/notebooks/dataportal.txt b/notebooks/dataportal.txt new file mode 100644 index 0000000..e69de29 diff --git a/notebooks/duals_EQ_TEBalance.csv b/notebooks/duals_EQ_TEBalance.csv new file mode 100644 index 0000000..c15872d --- /dev/null +++ b/notebooks/duals_EQ_TEBalance.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:49e7591811b1df32f8706b02d15b4aba052eee95c601286859855ce144200fa8 +size 601126 diff --git a/notebooks/model.ilp b/notebooks/model.ilp new file mode 100644 index 0000000..926d85d --- /dev/null +++ b/notebooks/model.ilp @@ -0,0 +1,669 @@ +\ Model x1_copy +\ LP format - for model browsing. Use MPS format to capture full model detail. +Minimize + +Subject To + c_l_x4676012_: 7.333880553651569 x4676013 >= 3503.990656024917 + c_u_x4677146_: x6004 <= 0.96 + c_u_x4709337_: - x1867375 - x1868719 - x1870063 - x1871407 + + 0.00688 x4676013 <= 0 + c_u_x4709338_: - x1867377 - x1868721 - x1870065 - x1871409 + + 0.00671 x4676013 <= 0 + c_u_x4709339_: - x1867379 - x1868723 - x1870067 - x1871411 + + 0.0066 x4676013 <= 0 + c_u_x4709340_: - x1867381 - x1868725 - x1870069 - x1871413 + + 0.00661 x4676013 <= 0 + c_u_x4709341_: - x1867383 - x1868727 - x1870071 - x1871415 + + 0.0069 x4676013 <= 0 + c_u_x4709342_: - x1867385 - x1868729 - x1870073 - x1871417 + + 0.00811 x4676013 <= 0 + c_u_x4709343_: - x1867387 - x1868731 - x1870075 - x1871419 + + 0.00984 x4676013 <= 0 + c_u_x4709344_: - x1867389 - x1868733 - x1870077 - x1871421 + + 0.01205 x4676013 <= 0 + c_u_x4709345_: - x1867391 - x1868735 - x1870079 - x1871423 + + 0.01374 x4676013 <= 0 + c_u_x4709346_: - x1867393 - x1868737 - x1870081 - x1871425 + + 0.01441 x4676013 <= 0 + c_u_x4709347_: - x1867395 - x1868739 - x1870083 - x1871427 + + 0.01441 x4676013 <= 0 + c_u_x4709348_: - x1867397 - x1868741 - x1870085 - x1871429 + + 0.01445 x4676013 <= 0 + c_u_x4709349_: - x1867399 - x1868743 - x1870087 - x1871431 + + 0.01372 x4676013 <= 0 + c_u_x4709350_: - x1867401 - x1868745 - x1870089 - x1871433 + + 0.01237 x4676013 <= 0 + c_u_x4709351_: - x1867403 - x1868747 - x1870091 - x1871435 + + 0.01224 x4676013 <= 0 + c_u_x4709352_: - x1867405 - x1868749 - x1870093 - x1871437 + + 0.01233 x4676013 <= 0 + c_u_x4709353_: - x1867407 - x1868751 - x1870095 - x1871439 + + 0.01223 x4676013 <= 0 + c_u_x4709354_: - x1867409 - x1868753 - x1870097 - x1871441 + + 0.01159 x4676013 <= 0 + c_u_x4709355_: - x1867411 - x1868755 - x1870099 - x1871443 + + 0.01091 x4676013 <= 0 + c_u_x4709356_: - x1867413 - x1868757 - x1870101 - x1871445 + + 0.01044 x4676013 <= 0 + c_u_x4709357_: - x1867415 - x1868759 - x1870103 - x1871447 + + 0.01006 x4676013 <= 0 + c_u_x4709358_: - x1867417 - x1868761 - x1870105 - x1871449 + + 0.00856 x4676013 <= 0 + c_u_x4709359_: - x1867419 - x1868763 - x1870107 - x1871451 + + 0.00761 x4676013 <= 0 + c_u_x4709360_: - x1867421 - x1868765 - x1870109 - x1871453 + + 0.00723 x4676013 <= 0 + c_u_x4709361_: - x1867423 - x1868767 - x1870111 - x1871455 + + 0.00714 x4676013 <= 0 + c_u_x4709362_: - x1867425 - x1868769 - x1870113 - x1871457 + + 0.00683 x4676013 <= 0 + c_u_x4709363_: - x1867427 - x1868771 - x1870115 - x1871459 + + 0.00667 x4676013 <= 0 + c_u_x4709364_: - x1867429 - x1868773 - x1870117 - x1871461 + + 0.00663 x4676013 <= 0 + c_u_x4709365_: - x1867431 - x1868775 - x1870119 - x1871463 + + 0.00686 x4676013 <= 0 + c_u_x4709366_: - x1867433 - x1868777 - x1870121 - x1871465 + + 0.00787 x4676013 <= 0 + c_u_x4709367_: - x1867435 - x1868779 - x1870123 - x1871467 + + 0.00923 x4676013 <= 0 + c_u_x4709368_: - x1867437 - x1868781 - x1870125 - x1871469 + + 0.01118 x4676013 <= 0 + c_u_x4709369_: - x1867439 - x1868783 - x1870127 - x1871471 + + 0.01256 x4676013 <= 0 + c_u_x4709370_: - x1867441 - x1868785 - x1870129 - x1871473 + + 0.01355 x4676013 <= 0 + c_u_x4709371_: - x1867443 - x1868787 - x1870131 - x1871475 + + 0.01404 x4676013 <= 0 + c_u_x4709372_: - x1867445 - x1868789 - x1870133 - x1871477 + + 0.01429 x4676013 <= 0 + c_u_x4709373_: - x1867447 - x1868791 - x1870135 - x1871479 + + 0.01396 x4676013 <= 0 + c_u_x4709374_: - x1867449 - x1868793 - x1870137 - x1871481 + + 0.01289 x4676013 <= 0 + c_u_x4709375_: - x1867451 - x1868795 - x1870139 - x1871483 + + 0.01227 x4676013 <= 0 + c_u_x4709376_: - x1867453 - x1868797 - x1870141 - x1871485 + + 0.01218 x4676013 <= 0 + c_u_x4709377_: - x1867455 - x1868799 - x1870143 - x1871487 + + 0.01222 x4676013 <= 0 + c_u_x4709378_: - x1867457 - x1868801 - x1870145 - x1871489 + + 0.01189 x4676013 <= 0 + c_u_x4709379_: - x1867459 - x1868803 - x1870147 - x1871491 + + 0.01142 x4676013 <= 0 + c_u_x4709380_: - x1867461 - x1868805 - x1870149 - x1871493 + + 0.01091 x4676013 <= 0 + c_u_x4709381_: - x1867463 - x1868807 - x1870151 - x1871495 + + 0.01054 x4676013 <= 0 + c_u_x4709382_: - x1867465 - x1868809 - x1870153 - x1871497 + + 0.00933 x4676013 <= 0 + c_u_x4709383_: - x1867467 - x1868811 - x1870155 - x1871499 + + 0.00836 x4676013 <= 0 + c_u_x4709384_: - x1867469 - x1868813 - x1870157 - x1871501 + + 0.00719 x4676013 <= 0 + c_u_x4709385_: - x1867471 - x1868815 - x1870159 - x1871503 + + 0.00598 x4676013 <= 0 + c_u_x4709386_: - x1867473 - x1868817 - x1870161 - x1871505 + + 0.00578 x4676013 <= 0 + c_u_x4709387_: - x1867475 - x1868819 - x1870163 - x1871507 + + 0.00568 x4676013 <= 0 + c_u_x4709388_: - x1867477 - x1868821 - x1870165 - x1871509 + + 0.00564 x4676013 <= 0 + c_u_x4709389_: - x1867479 - x1868823 - x1870167 - x1871511 + + 0.00569 x4676013 <= 0 + c_u_x4709390_: - x1867481 - x1868825 - x1870169 - x1871513 + + 0.00602 x4676013 <= 0 + c_u_x4709391_: - x1867483 - x1868827 - x1870171 - x1871515 + + 0.00736 x4676013 <= 0 + c_u_x4709392_: - x1867485 - x1868829 - x1870173 - x1871517 + + 0.00965 x4676013 <= 0 + c_u_x4709393_: - x1867487 - x1868831 - x1870175 - x1871519 + + 0.01272 x4676013 <= 0 + c_u_x4709394_: - x1867489 - x1868833 - x1870177 - x1871521 + + 0.01443 x4676013 <= 0 + c_u_x4709395_: - x1867491 - x1868835 - x1870179 - x1871523 + + 0.01512 x4676013 <= 0 + c_u_x4709396_: - x1867493 - x1868837 - x1870181 - x1871525 + + 0.01518 x4676013 <= 0 + c_u_x4709397_: - x1867495 - x1868839 - x1870183 - x1871527 + + 0.01506 x4676013 <= 0 + c_u_x4709398_: - x1867497 - x1868841 - x1870185 - x1871529 + + 0.01415 x4676013 <= 0 + c_u_x4709399_: - x1867499 - x1868843 - x1870187 - x1871531 + + 0.01263 x4676013 <= 0 + c_u_x4709400_: - x1867501 - x1868845 - x1870189 - x1871533 + + 0.01228 x4676013 <= 0 + c_u_x4709401_: - x1867503 - x1868847 - x1870191 - x1871535 + + 0.01244 x4676013 <= 0 + c_u_x4709402_: - x1867505 - x1868849 - x1870193 - x1871537 + + 0.01285 x4676013 <= 0 + c_u_x4709403_: - x1867507 - x1868851 - x1870195 - x1871539 + + 0.01322 x4676013 <= 0 + c_u_x4709404_: - x1867509 - x1868853 - x1870197 - x1871541 + + 0.01242 x4676013 <= 0 + c_u_x4709405_: - x1867511 - x1868855 - x1870199 - x1871543 + + 0.01112 x4676013 <= 0 + c_u_x4709406_: - x1867513 - x1868857 - x1870201 - x1871545 + + 0.00945 x4676013 <= 0 + c_u_x4709407_: - x1867515 - x1868859 - x1870203 - x1871547 + + 0.00798 x4676013 <= 0 + c_u_x4709408_: - x1867517 - x1868861 - x1870205 - x1871549 + + 0.00715 x4676013 <= 0 + c_u_x4709409_: - x1867519 - x1868863 - x1870207 - x1871551 + + 0.00591 x4676013 <= 0 + c_u_x4709410_: - x1867521 - x1868865 - x1870209 - x1871553 + + 0.00572 x4676013 <= 0 + c_u_x4709411_: - x1867523 - x1868867 - x1870211 - x1871555 + + 0.00562 x4676013 <= 0 + c_u_x4709412_: - x1867525 - x1868869 - x1870213 - x1871557 + + 0.00559 x4676013 <= 0 + c_u_x4709413_: - x1867527 - x1868871 - x1870215 - x1871559 + + 0.00566 x4676013 <= 0 + c_u_x4709414_: - x1867529 - x1868873 - x1870217 - x1871561 + + 0.00601 x4676013 <= 0 + c_u_x4709415_: - x1867531 - x1868875 - x1870219 - x1871563 + + 0.00739 x4676013 <= 0 + c_u_x4709416_: - x1867533 - x1868877 - x1870221 - x1871565 + + 0.00989 x4676013 <= 0 + c_u_x4709417_: - x1867535 - x1868879 - x1870223 - x1871567 + + 0.01322 x4676013 <= 0 + c_u_x4709418_: - x1867537 - x1868881 - x1870225 - x1871569 + + 0.01506 x4676013 <= 0 + c_u_x4709419_: - x1867539 - x1868883 - x1870227 - x1871571 + + 0.01568 x4676013 <= 0 + c_u_x4709420_: - x1867541 - x1868885 - x1870229 - x1871573 + + 0.01561 x4676013 <= 0 + c_u_x4709421_: - x1867543 - x1868887 - x1870231 - x1871575 + + 0.01535 x4676013 <= 0 + c_u_x4709422_: - x1867545 - x1868889 - x1870233 - x1871577 + + 0.01427 x4676013 <= 0 + c_u_x4709423_: - x1867547 - x1868891 - x1870235 - x1871579 + + 0.01262 x4676013 <= 0 + c_u_x4709424_: - x1867549 - x1868893 - x1870237 - x1871581 + + 0.01213 x4676013 <= 0 + c_u_x4709425_: - x1867551 - x1868895 - x1870239 - x1871583 + + 0.01223 x4676013 <= 0 + c_u_x4709426_: - x1867553 - x1868897 - x1870241 - x1871585 + + 0.01238 x4676013 <= 0 + c_u_x4709427_: - x1867555 - x1868899 - x1870243 - x1871587 + + 0.01271 x4676013 <= 0 + c_u_x4709428_: - x1867557 - x1868901 - x1870245 - x1871589 + + 0.01221 x4676013 <= 0 + c_u_x4709429_: - x1867559 - x1868903 - x1870247 - x1871591 + + 0.01091 x4676013 <= 0 + c_u_x4709430_: - x1867561 - x1868905 - x1870249 - x1871593 + + 0.00925 x4676013 <= 0 + c_u_x4709431_: - x1867563 - x1868907 - x1870251 - x1871595 + + 0.00772 x4676013 <= 0 + c_u_x4709432_: - x1867565 - x1868909 - x1870253 - x1871597 + + 0.00688 x4676013 <= 0 + c_u_x5140069_: x1867375 + x1867377 + x1867379 + x1867381 + x1867383 + + x1867385 + x1867387 + x1867389 + x1867391 + x1867393 + x1867395 + + x1867397 + x1867399 + x1867401 + x1867403 + x1867405 + x1867407 + + x1867409 + x1867411 + x1867413 + x1867415 + x1867417 + x1867419 + + x1867421 + x1867423 + x1867425 + x1867427 + x1867429 + x1867431 + + x1867433 + x1867435 + x1867437 + x1867439 + x1867441 + x1867443 + + x1867445 + x1867447 + x1867449 + x1867451 + x1867453 + x1867455 + + x1867457 + x1867459 + x1867461 + x1867463 + x1867465 + x1867467 + + x1867469 + x1867471 + x1867473 + x1867475 + x1867477 + x1867479 + + x1867481 + x1867483 + x1867485 + x1867487 + x1867489 + x1867491 + + x1867493 + x1867495 + x1867497 + x1867499 + x1867501 + x1867503 + + x1867505 + x1867507 + x1867509 + x1867511 + x1867513 + x1867515 + + x1867517 + x1867519 + x1867521 + x1867523 + x1867525 + x1867527 + + x1867529 + x1867531 + x1867533 + x1867535 + x1867537 + x1867539 + + x1867541 + x1867543 + x1867545 + x1867547 + x1867549 + x1867551 + + x1867553 + x1867555 + x1867557 + x1867559 + x1867561 + x1867563 + + x1867565 - 50 x4677148 <= 0 + c_u_x5140077_: x1868719 + x1868721 + x1868723 + x1868725 + x1868727 + + x1868729 + x1868731 + x1868733 + x1868735 + x1868737 + x1868739 + + x1868741 + x1868743 + x1868745 + x1868747 + x1868749 + x1868751 + + x1868753 + x1868755 + x1868757 + x1868759 + x1868761 + x1868763 + + x1868765 + x1868767 + x1868769 + x1868771 + x1868773 + x1868775 + + x1868777 + x1868779 + x1868781 + x1868783 + x1868785 + x1868787 + + x1868789 + x1868791 + x1868793 + x1868795 + x1868797 + x1868799 + + x1868801 + x1868803 + x1868805 + x1868807 + x1868809 + x1868811 + + x1868813 + x1868815 + x1868817 + x1868819 + x1868821 + x1868823 + + x1868825 + x1868827 + x1868829 + x1868831 + x1868833 + x1868835 + + x1868837 + x1868839 + x1868841 + x1868843 + x1868845 + x1868847 + + x1868849 + x1868851 + x1868853 + x1868855 + x1868857 + x1868859 + + x1868861 + x1868863 + x1868865 + x1868867 + x1868869 + x1868871 + + x1868873 + x1868875 + x1868877 + x1868879 + x1868881 + x1868883 + + x1868885 + x1868887 + x1868889 + x1868891 + x1868893 + x1868895 + + x1868897 + x1868899 + x1868901 + x1868903 + x1868905 + x1868907 + + x1868909 - 50 x4677149 <= 0 + c_u_x5140085_: x1870063 + x1870065 + x1870067 + x1870069 + x1870071 + + x1870073 + x1870075 + x1870077 + x1870079 + x1870081 + x1870083 + + x1870085 + x1870087 + x1870089 + x1870091 + x1870093 + x1870095 + + x1870097 + x1870099 + x1870101 + x1870103 + x1870105 + x1870107 + + x1870109 + x1870111 + x1870113 + x1870115 + x1870117 + x1870119 + + x1870121 + x1870123 + x1870125 + x1870127 + x1870129 + x1870131 + + x1870133 + x1870135 + x1870137 + x1870139 + x1870141 + x1870143 + + x1870145 + x1870147 + x1870149 + x1870151 + x1870153 + x1870155 + + x1870157 + x1870159 + x1870161 + x1870163 + x1870165 + x1870167 + + x1870169 + x1870171 + x1870173 + x1870175 + x1870177 + x1870179 + + x1870181 + x1870183 + x1870185 + x1870187 + x1870189 + x1870191 + + x1870193 + x1870195 + x1870197 + x1870199 + x1870201 + x1870203 + + x1870205 + x1870207 + x1870209 + x1870211 + x1870213 + x1870215 + + x1870217 + x1870219 + x1870221 + x1870223 + x1870225 + x1870227 + + x1870229 + x1870231 + x1870233 + x1870235 + x1870237 + x1870239 + + x1870241 + x1870243 + x1870245 + x1870247 + x1870249 + x1870251 + + x1870253 - 50 x4677150 <= 0 + c_u_x5140093_: x1871407 + x1871409 + x1871411 + x1871413 + x1871415 + + x1871417 + x1871419 + x1871421 + x1871423 + x1871425 + x1871427 + + x1871429 + x1871431 + x1871433 + x1871435 + x1871437 + x1871439 + + x1871441 + x1871443 + x1871445 + x1871447 + x1871449 + x1871451 + + x1871453 + x1871455 + x1871457 + x1871459 + x1871461 + x1871463 + + x1871465 + x1871467 + x1871469 + x1871471 + x1871473 + x1871475 + + x1871477 + x1871479 + x1871481 + x1871483 + x1871485 + x1871487 + + x1871489 + x1871491 + x1871493 + x1871495 + x1871497 + x1871499 + + x1871501 + x1871503 + x1871505 + x1871507 + x1871509 + x1871511 + + x1871513 + x1871515 + x1871517 + x1871519 + x1871521 + x1871523 + + x1871525 + x1871527 + x1871529 + x1871531 + x1871533 + x1871535 + + x1871537 + x1871539 + x1871541 + x1871543 + x1871545 + x1871547 + + x1871549 + x1871551 + x1871553 + x1871555 + x1871557 + x1871559 + + x1871561 + x1871563 + x1871565 + x1871567 + x1871569 + x1871571 + + x1871573 + x1871575 + x1871577 + x1871579 + x1871581 + x1871583 + + x1871585 + x1871587 + x1871589 + x1871591 + x1871593 + x1871595 + + x1871597 - 50 x4677151 <= 0 + c_e_x5142343_: x6005 + x4677148 = 0 + c_e_x5142350_: x6006 + x4677149 = 0 + c_e_x5142357_: x6007 + x4677150 = 0.8 + c_e_x5142364_: - x6004 + x4677151 = 0 + c_e_x5146606_: x6005 = 0 + c_e_x5146613_: x6006 = 0 + c_e_x5146620_: x6007 = 0.08 +Bounds + x6004 free + x6005 free + x6006 free + x6007 free + x1867375 free + x1867377 free + x1867379 free + x1867381 free + x1867383 free + x1867385 free + x1867387 free + x1867389 free + x1867391 free + x1867393 free + x1867395 free + x1867397 free + x1867399 free + x1867401 free + x1867403 free + x1867405 free + x1867407 free + x1867409 free + x1867411 free + x1867413 free + x1867415 free + x1867417 free + x1867419 free + x1867421 free + x1867423 free + x1867425 free + x1867427 free + x1867429 free + x1867431 free + x1867433 free + x1867435 free + x1867437 free + x1867439 free + x1867441 free + x1867443 free + x1867445 free + x1867447 free + x1867449 free + x1867451 free + x1867453 free + x1867455 free + x1867457 free + x1867459 free + x1867461 free + x1867463 free + x1867465 free + x1867467 free + x1867469 free + x1867471 free + x1867473 free + x1867475 free + x1867477 free + x1867479 free + x1867481 free + x1867483 free + x1867485 free + x1867487 free + x1867489 free + x1867491 free + x1867493 free + x1867495 free + x1867497 free + x1867499 free + x1867501 free + x1867503 free + x1867505 free + x1867507 free + x1867509 free + x1867511 free + x1867513 free + x1867515 free + x1867517 free + x1867519 free + x1867521 free + x1867523 free + x1867525 free + x1867527 free + x1867529 free + x1867531 free + x1867533 free + x1867535 free + x1867537 free + x1867539 free + x1867541 free + x1867543 free + x1867545 free + x1867547 free + x1867549 free + x1867551 free + x1867553 free + x1867555 free + x1867557 free + x1867559 free + x1867561 free + x1867563 free + x1867565 free + x1868719 free + x1868721 free + x1868723 free + x1868725 free + x1868727 free + x1868729 free + x1868731 free + x1868733 free + x1868735 free + x1868737 free + x1868739 free + x1868741 free + x1868743 free + x1868745 free + x1868747 free + x1868749 free + x1868751 free + x1868753 free + x1868755 free + x1868757 free + x1868759 free + x1868761 free + x1868763 free + x1868765 free + x1868767 free + x1868769 free + x1868771 free + x1868773 free + x1868775 free + x1868777 free + x1868779 free + x1868781 free + x1868783 free + x1868785 free + x1868787 free + x1868789 free + x1868791 free + x1868793 free + x1868795 free + x1868797 free + x1868799 free + x1868801 free + x1868803 free + x1868805 free + x1868807 free + x1868809 free + x1868811 free + x1868813 free + x1868815 free + x1868817 free + x1868819 free + x1868821 free + x1868823 free + x1868825 free + x1868827 free + x1868829 free + x1868831 free + x1868833 free + x1868835 free + x1868837 free + x1868839 free + x1868841 free + x1868843 free + x1868845 free + x1868847 free + x1868849 free + x1868851 free + x1868853 free + x1868855 free + x1868857 free + x1868859 free + x1868861 free + x1868863 free + x1868865 free + x1868867 free + x1868869 free + x1868871 free + x1868873 free + x1868875 free + x1868877 free + x1868879 free + x1868881 free + x1868883 free + x1868885 free + x1868887 free + x1868889 free + x1868891 free + x1868893 free + x1868895 free + x1868897 free + x1868899 free + x1868901 free + x1868903 free + x1868905 free + x1868907 free + x1868909 free + x1870063 free + x1870065 free + x1870067 free + x1870069 free + x1870071 free + x1870073 free + x1870075 free + x1870077 free + x1870079 free + x1870081 free + x1870083 free + x1870085 free + x1870087 free + x1870089 free + x1870091 free + x1870093 free + x1870095 free + x1870097 free + x1870099 free + x1870101 free + x1870103 free + x1870105 free + x1870107 free + x1870109 free + x1870111 free + x1870113 free + x1870115 free + x1870117 free + x1870119 free + x1870121 free + x1870123 free + x1870125 free + x1870127 free + x1870129 free + x1870131 free + x1870133 free + x1870135 free + x1870137 free + x1870139 free + x1870141 free + x1870143 free + x1870145 free + x1870147 free + x1870149 free + x1870151 free + x1870153 free + x1870155 free + x1870157 free + x1870159 free + x1870161 free + x1870163 free + x1870165 free + x1870167 free + x1870169 free + x1870171 free + x1870173 free + x1870175 free + x1870177 free + x1870179 free + x1870181 free + x1870183 free + x1870185 free + x1870187 free + x1870189 free + x1870191 free + x1870193 free + x1870195 free + x1870197 free + x1870199 free + x1870201 free + x1870203 free + x1870205 free + x1870207 free + x1870209 free + x1870211 free + x1870213 free + x1870215 free + x1870217 free + x1870219 free + x1870221 free + x1870223 free + x1870225 free + x1870227 free + x1870229 free + x1870231 free + x1870233 free + x1870235 free + x1870237 free + x1870239 free + x1870241 free + x1870243 free + x1870245 free + x1870247 free + x1870249 free + x1870251 free + x1870253 free + x1871407 free + x1871409 free + x1871411 free + x1871413 free + x1871415 free + x1871417 free + x1871419 free + x1871421 free + x1871423 free + x1871425 free + x1871427 free + x1871429 free + x1871431 free + x1871433 free + x1871435 free + x1871437 free + x1871439 free + x1871441 free + x1871443 free + x1871445 free + x1871447 free + x1871449 free + x1871451 free + x1871453 free + x1871455 free + x1871457 free + x1871459 free + x1871461 free + x1871463 free + x1871465 free + x1871467 free + x1871469 free + x1871471 free + x1871473 free + x1871475 free + x1871477 free + x1871479 free + x1871481 free + x1871483 free + x1871485 free + x1871487 free + x1871489 free + x1871491 free + x1871493 free + x1871495 free + x1871497 free + x1871499 free + x1871501 free + x1871503 free + x1871505 free + x1871507 free + x1871509 free + x1871511 free + x1871513 free + x1871515 free + x1871517 free + x1871519 free + x1871521 free + x1871523 free + x1871525 free + x1871527 free + x1871529 free + x1871531 free + x1871533 free + x1871535 free + x1871537 free + x1871539 free + x1871541 free + x1871543 free + x1871545 free + x1871547 free + x1871549 free + x1871551 free + x1871553 free + x1871555 free + x1871557 free + x1871559 free + x1871561 free + x1871563 free + x1871565 free + x1871567 free + x1871569 free + x1871571 free + x1871573 free + x1871575 free + x1871577 free + x1871579 free + x1871581 free + x1871583 free + x1871585 free + x1871587 free + x1871589 free + x1871591 free + x1871593 free + x1871595 free + x1871597 free + x4676013 free + x4677148 free + x4677149 free + x4677150 free + x4677151 free +End diff --git a/notebooks/output.csv b/notebooks/output.csv new file mode 100644 index 0000000..2efcfcf --- /dev/null +++ b/notebooks/output.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f61f07affbf225c7eaea1fa3f634a67261edc181f6d331a4ecd5ff2923991815 +size 1275611674 diff --git a/notebooks/quickstart_openMASTER.ipynb b/notebooks/quickstart_openMASTER.ipynb index 069010d..5944b7f 100644 --- a/notebooks/quickstart_openMASTER.ipynb +++ b/notebooks/quickstart_openMASTER.ipynb @@ -41,7 +41,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 2, @@ -74,339 +74,6878 @@ "cell_type": "code", "execution_count": 3, "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:424: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.\n", + "The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.\n", + "\n", + "For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.\n", + "\n", + "\n", + " temp_values[sheetname].fillna(0.0, inplace = True)\n", + "c:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\openMASTER\\loader.py:426: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.\n", + " data_list = pd.concat([data_list, temp_values], ignore_index=True)\n" + ] + } + ], + "source": [ + "data = openMASTER.load_dataportal_from_excel('../data/input/openMASTER_Data_2050_v1_STPathway.xlsx')\n", + "# data = openMASTER.load_dataportal_from_csv()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Create the instance of the abstract model " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "instance = m.create_instance(data)\n", + "instance.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Execute this if infeasible model is detected\n", + "# pyo.SolverFactory('gurobi_persistent')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Solve the model instance\n", + "\n", + "To solve the model instance, please select a solver within the Pyomo SolverFactory. Please note that any solver has to be previously installed." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Set parameter Username\n", + "Academic license - for non-commercial use only - expires 2024-11-22\n", + "Read LP format model from file C:\\Users\\marios\\AppData\\Local\\Temp\\tmpianhyypz.pyomo.lp\n", + "Reading time = 9.30 seconds\n", + "x1: 3168206 rows, 2116851 columns, 9657209 nonzeros\n", + "Set parameter QCPDual to value 1\n", + "Gurobi Optimizer version 11.0.0 build v11.0.0rc2 (win64 - Windows 11+.0 (26100.2))\n", + "\n", + "CPU model: Intel(R) Core(TM) i7-8700 CPU @ 3.20GHz, instruction set [SSE2|AVX|AVX2]\n", + "Thread count: 6 physical cores, 12 logical processors, using up to 12 threads\n", + "\n", + "Optimize a model with 3168206 rows, 2116851 columns and 9657209 nonzeros\n", + "Model fingerprint: 0xd7eafcdf\n", + "Coefficient statistics:\n", + " Matrix range [3e-06, 5e+09]\n", + " Objective range [1e+00, 1e+00]\n", + " Bounds range [1e+00, 1e+00]\n", + " RHS range [5e-05, 3e+05]\n", + "Warning: Model contains large matrix coefficient range\n", + " Consider reformulating model or setting NumericFocus parameter\n", + " to avoid numerical issues.\n", + "Presolve removed 2830502 rows and 1713341 columns\n", + "Presolve time: 4.52s\n", + "Presolved: 337704 rows, 403589 columns, 2836516 nonzeros\n", + "\n", + "Concurrent LP optimizer: primal simplex, dual simplex, and barrier\n", + "Showing barrier log only...\n", + "\n", + "Ordering time: 7.90s\n", + "Elapsed ordering time = 8s\n", + "Elapsed ordering time = 10s\n", + "Elapsed ordering time = 15s\n", + "Ordering time: 16.57s\n", + "\n", + "Barrier statistics:\n", + " Dense cols : 378\n", + " AA' NZ : 7.493e+06\n", + " Factor NZ : 4.020e+07 (roughly 600 MB of memory)\n", + " Factor Ops : 3.157e+10 (roughly 1 second per iteration)\n", + " Threads : 4\n", + "\n", + " Objective Residual\n", + "Iter Primal Dual Primal Dual Compl Time\n", + " 0 5.13479581e+18 -8.44934004e+18 7.55e+10 6.88e+08 4.92e+16 24s\n", + " 1 5.14531904e+18 -8.55656129e+18 6.57e+10 4.06e+09 4.32e+16 25s\n", + " 2 5.23155062e+18 -8.62930694e+18 5.22e+10 3.76e+09 3.55e+16 26s\n", + " 3 5.74376572e+18 -8.84360892e+18 3.71e+10 2.71e+09 2.55e+16 27s\n", + " 4 6.17129893e+18 -8.90730873e+18 2.40e+10 2.21e+09 1.73e+16 27s\n", + " 5 6.37257826e+18 -8.98638713e+18 1.78e+10 1.90e+09 1.33e+16 28s\n", + " 6 6.54739902e+18 -9.17873919e+18 1.16e+10 1.21e+09 8.74e+15 29s\n", + " 7 6.49251344e+18 -9.26399134e+18 7.59e+09 8.02e+08 5.79e+15 29s\n", + " 8 6.05704901e+18 -9.26898117e+18 3.98e+09 5.78e+08 3.27e+15 30s\n", + " 9 5.72408123e+18 -9.11080022e+18 2.72e+09 3.52e+08 2.17e+15 31s\n", + " 10 5.10795311e+18 -8.88193412e+18 1.47e+09 2.04e+08 1.21e+15 32s\n", + " 11 4.70515331e+18 -8.47437545e+18 1.07e+09 1.13e+08 8.53e+14 32s\n", + " 12 4.10003279e+18 -7.84292290e+18 6.32e+08 6.25e+07 5.09e+14 33s\n", + " 13 3.74591837e+18 -7.40115305e+18 4.68e+08 4.45e+07 3.83e+14 34s\n", + " 14 2.59506082e+18 -6.88284245e+18 1.43e+08 3.41e+07 1.43e+14 34s\n", + " 15 2.28587086e+18 -5.03993751e+18 9.01e+07 1.63e+07 8.81e+13 35s\n", + " 16 1.84338893e+18 -4.16205763e+18 4.62e+07 1.04e+07 5.00e+13 37s\n", + " 17 1.40415525e+18 -2.49081992e+18 2.16e+07 4.11e+06 2.36e+13 38s\n", + " 18 1.14093782e+18 -1.92406028e+18 1.48e+07 1.73e+06 1.70e+13 39s\n", + " 19 9.13311019e+17 -1.51615406e+18 9.82e+06 1.19e+06 1.26e+13 40s\n", + " 20 8.62526246e+17 -1.31326731e+18 8.78e+06 1.31e+06 1.14e+13 41s\n", + " 21 7.56994321e+17 -1.28095984e+18 6.62e+06 1.26e+06 9.86e+12 42s\n", + " 22 6.63613437e+17 -9.36019288e+17 5.05e+06 1.63e+06 8.24e+12 44s\n", + " 23 4.66767163e+17 -8.99749608e+17 1.66e+06 1.50e+06 5.84e+12 45s\n", + " 24 4.00855214e+17 -8.48362236e+17 4.88e+05 1.37e+06 4.99e+12 46s\n", + " 25 3.42300446e+17 -6.01900381e+17 1.90e+05 7.57e+05 3.96e+12 48s\n", + " 26 2.97441415e+17 -4.78876219e+17 1.65e+05 3.61e+05 3.35e+12 49s\n", + " 27 2.39492760e+17 -3.66849771e+17 1.33e+05 4.03e+05 2.66e+12 51s\n", + " 28 1.53748771e+17 -2.62503917e+17 8.78e+04 1.82e+06 1.75e+12 52s\n", + " 29 1.25447308e+17 -2.39109769e+17 7.49e+04 2.40e+06 1.49e+12 54s\n", + " 30 1.09968166e+17 -2.27635601e+17 6.81e+04 2.22e+06 1.36e+12 56s\n", + " 31 9.18593972e+16 -2.22384670e+17 5.92e+04 2.24e+06 1.20e+12 57s\n", + " 32 7.75524358e+16 -1.89227101e+17 5.27e+04 1.73e+06 1.05e+12 58s\n", + " 33 5.04239328e+16 -1.40869780e+17 3.96e+04 1.02e+06 7.65e+11 60s\n", + " 34 2.76653162e+16 -9.62269889e+16 2.45e+04 4.66e+05 4.68e+11 61s\n", + " 35 1.62328297e+16 -8.15043532e+16 1.76e+04 3.29e+05 3.40e+11 62s\n", + " 36 1.82774570e+16 -5.28124197e+16 1.21e+04 1.61e+05 2.31e+11 63s\n", + " 37 1.42613128e+16 -3.75142396e+16 8.58e+03 9.26e+04 1.59e+11 65s\n", + " 38 1.02727385e+16 -3.23355427e+16 6.18e+03 7.23e+04 1.17e+11 66s\n", + " 39 8.83225838e+15 -2.58922150e+16 5.26e+03 5.00e+04 9.49e+10 67s\n", + " 40 8.18020587e+15 -2.55120180e+16 4.90e+03 4.88e+04 8.95e+10 68s\n", + " 41 5.01543702e+15 -2.01861912e+16 3.03e+03 2.80e+04 5.73e+10 69s\n", + " 42 2.62772444e+15 -1.86022785e+16 1.54e+03 2.35e+04 3.71e+10 70s\n", + " 43 2.01017107e+15 -1.22156488e+16 1.19e+03 1.63e+04 2.44e+10 71s\n", + " 44 9.86894231e+14 -9.30987096e+15 5.45e+02 1.74e+04 1.43e+10 73s\n", + " 45 6.66211417e+14 -5.19809073e+15 3.46e+02 7.72e+03 7.72e+09 74s\n", + " 46 4.79764190e+14 -3.65231901e+15 2.33e+02 5.10e+03 5.17e+09 75s\n", + " 47 3.95220559e+14 -2.66883124e+15 1.82e+02 3.66e+03 3.75e+09 76s\n", + " 48 2.57191734e+14 -2.48953350e+15 9.89e+01 3.40e+03 3.11e+09 77s\n", + " 49 2.45140807e+14 -2.00896337e+15 9.16e+01 2.72e+03 2.56e+09 78s\n", + " 50 1.84815060e+14 -1.56677947e+15 5.54e+01 2.24e+03 1.92e+09 79s\n", + " 51 1.45063739e+14 -1.28806847e+15 7.94e+01 2.02e+03 1.52e+09 80s\n", + " 52 1.20993544e+14 -4.53858924e+14 2.08e+01 7.25e+02 6.03e+08 82s\n", + " 53 1.07793254e+14 -4.07663658e+14 1.48e+01 6.60e+02 5.32e+08 83s\n", + " 54 1.01666686e+14 -3.67561285e+14 1.25e+01 6.04e+02 4.83e+08 84s\n", + " 55 9.61849142e+13 -2.45801858e+14 1.00e+01 4.32e+02 3.50e+08 85s\n", + " 56 8.99520664e+13 -1.62175052e+14 7.08e+00 3.14e+02 2.57e+08 86s\n", + " 57 8.50402247e+13 -1.30671762e+14 4.57e+00 2.70e+02 2.19e+08 87s\n", + " 58 8.15742153e+13 -5.93990563e+13 3.44e+00 1.72e+02 1.43e+08 87s\n", + " 59 7.83851504e+13 -3.12032994e+13 2.59e+00 1.33e+02 1.11e+08 88s\n", + " 60 7.55653150e+13 -3.53279263e+12 1.99e+00 9.41e+01 7.98e+07 89s\n", + " 61 7.37988331e+13 5.84296894e+12 1.57e+00 8.13e+01 6.84e+07 90s\n", + " 62 7.29824697e+13 1.89492027e+13 1.37e+00 6.34e+01 5.44e+07 92s\n", + " 63 7.14461252e+13 2.12348263e+13 1.07e+00 5.99e+01 5.04e+07 93s\n", + " 64 7.06839930e+13 3.06241397e+13 9.37e-01 4.72e+01 4.02e+07 94s\n", + " 65 7.00026561e+13 3.42559893e+13 7.99e-01 4.21e+01 3.59e+07 95s\n", + " 66 6.94954040e+13 3.65103944e+13 7.20e-01 3.90e+01 3.31e+07 96s\n", + " 67 6.85916415e+13 4.20194409e+13 5.50e-01 3.12e+01 2.66e+07 97s\n", + " 68 6.77608936e+13 4.76343250e+13 4.38e-01 2.29e+01 2.02e+07 98s\n", + " 69 6.69502137e+13 4.92153469e+13 3.30e-01 2.08e+01 1.78e+07 99s\n", + " 70 6.63765994e+13 5.12081822e+13 2.52e-01 1.80e+01 1.52e+07 101s\n", + " 71 6.60343037e+13 5.45205037e+13 2.14e-01 1.31e+01 1.15e+07 102s\n", + " 72 6.57404217e+13 5.49371309e+13 1.80e-01 1.25e+01 1.08e+07 103s\n", + " 73 6.54931783e+13 5.63911090e+13 1.48e-01 1.05e+01 9.10e+06 104s\n", + " 74 6.53805201e+13 5.83675372e+13 1.32e-01 7.78e+00 7.01e+06 105s\n", + " 75 6.50523639e+13 5.90085958e+13 9.68e-02 6.86e+00 6.04e+06 107s\n", + " 76 6.49795096e+13 5.96485425e+13 9.04e-02 5.97e+00 5.33e+06 108s\n", + " 77 6.48272703e+13 6.04895262e+13 7.69e-02 4.73e+00 4.33e+06 109s\n", + " 78 6.47029542e+13 6.12623371e+13 6.83e-02 3.53e+00 3.44e+06 111s\n", + " 79 6.44352411e+13 6.19225685e+13 5.38e-02 2.37e+00 2.51e+06 112s\n", + " 80 6.41279399e+13 6.21809947e+13 3.70e-02 1.86e+00 1.94e+06 113s\n", + " 81 6.40394354e+13 6.23544379e+13 3.20e-02 1.59e+00 1.68e+06 114s\n", + " 82 6.38273144e+13 6.27435522e+13 2.06e-02 9.97e-01 1.08e+06 115s\n", + " 83 6.37703216e+13 6.29293154e+13 1.73e-02 7.08e-01 8.38e+05 116s\n", + " 84 6.36852489e+13 6.30478875e+13 1.29e-02 5.22e-01 6.35e+05 117s\n", + " 85 6.36436765e+13 6.31240226e+13 1.09e-02 4.07e-01 5.17e+05 118s\n", + " 86 6.36144246e+13 6.31936802e+13 9.48e-03 3.05e-01 4.19e+05 120s\n", + " 87 6.35848057e+13 6.32238406e+13 8.17e-03 2.62e-01 3.59e+05 121s\n", + " 88 6.35605480e+13 6.32347933e+13 7.12e-03 2.47e-01 3.24e+05 122s\n", + " 89 6.35364828e+13 6.32882920e+13 6.01e-03 1.65e-01 2.47e+05 124s\n", + " 90 6.35107736e+13 6.33103988e+13 4.75e-03 1.32e-01 1.99e+05 125s\n", + " 91 6.34982543e+13 6.33261584e+13 4.05e-03 1.11e-01 1.71e+05 127s\n", + " 92 6.34764541e+13 6.33474659e+13 2.96e-03 8.11e-02 1.28e+05 128s\n", + " 93 6.34680772e+13 6.33540605e+13 2.58e-03 7.18e-02 1.13e+05 130s\n", + " 94 6.34543611e+13 6.33730048e+13 1.94e-03 4.68e-02 8.08e+04 131s\n", + " 95 6.34506041e+13 6.33759426e+13 1.76e-03 4.32e-02 7.39e+04 132s\n", + " 96 6.34442173e+13 6.33850229e+13 1.47e-03 3.17e-02 5.84e+04 133s\n", + " 97 6.34395930e+13 6.33905650e+13 1.24e-03 2.55e-02 4.84e+04 135s\n", + " 98 6.34332557e+13 6.33948762e+13 9.60e-04 1.96e-02 3.79e+04 136s\n", + " 99 6.34290128e+13 6.34015902e+13 7.42e-04 1.23e-02 2.71e+04 137s\n", + " 100 6.34261427e+13 6.34047632e+13 6.00e-04 9.12e-03 2.11e+04 138s\n", + " 101 6.34243761e+13 6.34072487e+13 5.22e-04 6.69e-03 1.69e+04 139s\n", + " 102 6.34203955e+13 6.34079705e+13 3.52e-04 4.93e-03 1.16e+04 140s\n", + " 103 6.34196851e+13 6.34092879e+13 3.18e-04 3.99e-03 9.83e+03 142s\n", + " 104 6.34180649e+13 6.34110028e+13 2.16e-04 2.56e-03 6.75e+03 143s\n", + " 105 6.34172996e+13 6.34126626e+13 1.68e-04 1.38e-03 4.52e+03 144s\n", + " 106 6.34170314e+13 6.34133052e+13 1.57e-04 9.40e-04 3.66e+03 145s\n", + " 107 6.34160505e+13 6.34135954e+13 1.46e-04 7.37e-04 2.42e+03 146s\n", + " 108 6.34157497e+13 6.34137787e+13 1.67e-04 6.13e-04 1.95e+03 147s\n", + " 109 6.34155731e+13 6.34140916e+13 1.89e-04 3.92e-04 1.47e+03 148s\n", + " 110 6.34154583e+13 6.34142656e+13 1.64e-04 2.74e-04 1.18e+03 149s\n", + " 111 6.34152168e+13 6.34143769e+13 1.12e-04 2.00e-04 8.34e+02 150s\n", + " 112 6.34150769e+13 6.34144593e+13 8.39e-05 1.44e-04 6.14e+02 151s\n", + " 113 6.34149435e+13 6.34145276e+13 3.02e-05 9.87e-05 4.14e+02 152s\n", + " 114 6.34148910e+13 6.34145611e+13 2.37e-05 7.72e-05 3.28e+02 153s\n", + " 115 6.34148822e+13 6.34145737e+13 2.26e-05 6.96e-05 3.07e+02 154s\n", + " 116 6.34148194e+13 6.34146123e+13 1.08e-05 4.43e-05 2.06e+02 155s\n", + " 117 6.34148008e+13 6.34146305e+13 9.20e-06 3.34e-05 1.69e+02 156s\n", + " 118 6.34147930e+13 6.34146386e+13 8.36e-06 2.91e-05 1.54e+02 157s\n", + " 119 6.34147705e+13 6.34146506e+13 6.70e-06 2.12e-05 1.19e+02 158s\n", + " 120 6.34147602e+13 6.34146595e+13 5.79e-06 1.65e-05 1.00e+02 160s\n", + " 121 6.34147566e+13 6.34146660e+13 5.47e-06 1.27e-05 9.02e+01 161s\n", + " 122 6.34147276e+13 6.34146702e+13 3.01e-06 1.05e-05 5.71e+01 162s\n", + " 123 6.34147155e+13 6.34146747e+13 3.48e-06 8.11e-06 4.06e+01 164s\n", + " 124 6.34147104e+13 6.34146790e+13 2.46e-06 5.95e-06 3.13e+01 166s\n", + " 125 6.34147007e+13 6.34146829e+13 4.20e-05 3.98e-06 1.78e+01 168s\n", + " 126 6.34146949e+13 6.34146854e+13 2.81e-04 2.54e-06 9.48e+00 171s\n", + " 127 6.34146933e+13 6.34146867e+13 5.02e-04 2.28e-06 6.57e+00 173s\n", + " 128 6.34146928e+13 6.34146872e+13 5.71e-04 1.91e-06 5.56e+00 175s\n", + " 129 6.34146923e+13 6.34146881e+13 6.19e-04 1.25e-06 4.15e+00 176s\n", + " 130 6.34146917e+13 6.34146887e+13 5.83e-04 1.47e-06 2.94e+00 178s\n", + " 131 6.34146911e+13 6.34146893e+13 4.58e-04 1.25e-06 1.79e+00 180s\n", + " 132 6.34146909e+13 6.34146895e+13 4.06e-04 2.12e-06 1.39e+00 182s\n", + " 133 6.34146909e+13 6.34146896e+13 1.64e-03 1.57e-06 1.23e+00 185s\n", + " 134 6.34146907e+13 6.34146898e+13 1.13e-03 1.69e-06 8.48e-01 186s\n", + " 135 6.34146905e+13 6.34146901e+13 5.31e-04 9.54e-07 4.45e-01 188s\n", + " 136 6.34146905e+13 6.34146902e+13 2.56e-04 4.31e-06 2.58e-01 189s\n", + "\n", + "Barrier solved model in 136 iterations and 188.91 seconds (140.87 work units)\n", + "Optimal objective 6.34146905e+13\n", + "\n", + "Crossover log...\n", + "\n", + " 276385 DPushes remaining with DInf 0.0000000e+00 189s\n", + " 40566 DPushes remaining with DInf 0.0000000e+00 190s\n", + " 2055 DPushes remaining with DInf 0.0000000e+00 195s\n", + " 0 DPushes remaining with DInf 0.0000000e+00 197s\n", + "\n", + " 271203 PPushes remaining with PInf 1.3096900e+02 197s\n", + " 172597 PPushes remaining with PInf 2.6585524e+01 200s\n", + " 134208 PPushes remaining with PInf 1.4129092e+01 205s\n", + " 56755 PPushes remaining with PInf 1.1486918e+00 210s\n", + " 31594 PPushes remaining with PInf 3.2681851e-01 215s\n", + " 15915 PPushes remaining with PInf 2.1918151e-02 220s\n", + " 8651 PPushes remaining with PInf 1.6379090e-02 225s\n", + " 0 PPushes remaining with PInf 8.0915485e-03 228s\n", + "\n", + " Push phase complete: Pinf 8.0915485e-03, Dinf 8.8495249e+08 228s\n", + "\n", + "Iteration Objective Primal Inf. Dual Inf. Time\n", + " 381193 6.3414690e+13 0.000000e+00 8.849525e+08 229s\n", + " 382117 6.3414690e+13 0.000000e+00 1.848351e+07 231s\n", + " 384273 6.3414690e+13 0.000000e+00 4.661843e+05 235s\n", + " 386429 6.3414690e+13 0.000000e+00 1.820026e+05 241s\n", + " 387440 6.3414690e+13 0.000000e+00 1.590623e+06 245s\n", + " 388685 6.3414690e+13 0.000000e+00 1.789157e+04 250s\n", + " 389780 6.3414690e+13 0.000000e+00 5.876783e+05 255s\n", + " 391080 6.3414690e+13 0.000000e+00 1.458057e+06 260s\n", + " 392843 6.3414690e+13 0.000000e+00 3.954026e+04 266s\n", + " 393830 6.3414690e+13 0.000000e+00 1.311962e+04 271s\n", + " 394731 6.3414690e+13 0.000000e+00 1.013340e+05 276s\n", + " 395708 6.3414690e+13 0.000000e+00 9.513453e+03 281s\n", + " 396293 6.3414690e+13 0.000000e+00 1.825102e+03 285s\n", + " 397233 6.3414690e+13 0.000000e+00 1.313803e+04 291s\n", + " 398266 6.3414690e+13 0.000000e+00 5.394906e+04 296s\n", + " 399106 6.3414690e+13 0.000000e+00 2.417572e+04 301s\n", + " 399948 6.3414690e+13 0.000000e+00 5.352236e+03 306s\n", + " 400728 6.3414690e+13 0.000000e+00 1.647359e+04 310s\n", + " 401698 6.3414690e+13 0.000000e+00 6.657243e+03 315s\n", + " 402601 6.3414690e+13 0.000000e+00 2.903615e+03 321s\n", + " 403441 6.3414690e+13 0.000000e+00 1.966811e+04 326s\n", + " 404283 6.3414690e+13 0.000000e+00 2.544739e+03 330s\n", + " 405510 6.3414690e+13 0.000000e+00 1.440650e+03 336s\n", + " 406241 6.3414690e+13 0.000000e+00 2.007504e+04 341s\n", + " 407352 6.3414690e+13 0.000000e+00 5.010679e+03 345s\n", + " 408577 6.3414690e+13 0.000000e+00 4.570752e+03 351s\n", + " 409257 6.3414690e+13 0.000000e+00 1.016502e+04 355s\n", + " 410310 6.3414690e+13 0.000000e+00 4.076963e+03 361s\n", + " 411359 6.3414690e+13 0.000000e+00 4.819183e+03 366s\n", + " 412206 6.3414690e+13 0.000000e+00 6.254045e+03 370s\n", + " 413583 6.3414690e+13 0.000000e+00 3.063032e+02 375s\n", + " 415293 6.3414690e+13 0.000000e+00 5.308716e+04 381s\n", + " 416459 6.3414690e+13 0.000000e+00 7.342419e+03 385s\n", + " 417555 6.3414690e+13 0.000000e+00 3.787984e+02 391s\n", + " 418705 6.3414690e+13 0.000000e+00 1.301328e+05 396s\n", + " 420158 6.3414690e+13 0.000000e+00 5.414466e+02 401s\n", + " 421596 6.3414690e+13 0.000000e+00 4.642339e+02 406s\n", + " 423138 6.3414690e+13 0.000000e+00 3.795980e+03 410s\n", + " 424647 6.3414690e+13 0.000000e+00 6.140940e+02 415s\n", + " 426151 6.3414690e+13 0.000000e+00 1.506828e+03 421s\n", + " 427588 6.3414690e+13 0.000000e+00 8.515851e+04 426s\n", + " 429300 6.3414690e+13 0.000000e+00 2.681501e+02 431s\n", + " 430534 6.3414690e+13 0.000000e+00 1.087987e+02 436s\n", + " 431690 6.3414690e+13 0.000000e+00 1.275168e+02 440s\n", + " 433543 6.3414690e+13 0.000000e+00 1.677375e+01 446s\n", + " 436774 6.3414690e+13 0.000000e+00 2.688731e+02 451s\n", + " 440037 6.3414690e+13 0.000000e+00 1.006099e+00 455s\n", + "\n", + "Solved with barrier\n", + " 444798 6.3414690e+13 0.000000e+00 5.005593e-04 461s\n", + "Extra simplex iterations after uncrush: 201\n", + " 444999 6.3414690e+13 0.000000e+00 0.000000e+00 462s\n", + "\n", + "Solved in 444999 iterations and 461.56 seconds (431.56 work units)\n", + "Optimal objective 6.341469037e+13\n", + "Warning: unscaled dual violation = 2.93566e-05 and residual = 3.05176e-05\n", + "\n", + "Warning: unable to write requested result file 'model.ilp'\n", + "\n" + ] + } + ], + "source": [ + "solver = pyo.SolverFactory('gurobi')\n", + "solver.options['ResultFile'] = 'model.ilp'\n", + "\n", + "# Setting the feasibility tolerance\n", + "solver.options['FeasibilityTol'] = 1e-6 # example value\n", + "\n", + "# Setting the optimality tolerance (MIP gap)\n", + "# solver.options['MIPGap'] = 1e-5 # example value\n", + "\n", + "solver_results = solver.solve(instance, keepfiles=False, tee=True)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### **Results**" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Extract information on variables through the model output to .csv files" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "ename": "RuntimeError", + "evalue": "The Pyomo persistent interface to gurobi could not be found.", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mRuntimeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[6], line 3\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mpyomo\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mcontrib\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01miis\u001b[39;00m\n\u001b[0;32m 2\u001b[0m pyo\u001b[38;5;241m.\u001b[39mSolverFactory(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mgurobi_persistent\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m----> 3\u001b[0m \u001b[43mpyomo\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcontrib\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43miis\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mwrite_iis\u001b[49m\u001b[43m(\u001b[49m\u001b[43minstance\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mInfeasibilities.ilp\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msolver\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mgurobi\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", + "File \u001b[1;32mc:\\Users\\marios\\Miniconda3\\envs\\openMaster_H2Included\\lib\\site-packages\\pyomo\\contrib\\iis\\iis.py:67\u001b[0m, in \u001b[0;36mwrite_iis\u001b[1;34m(pyomo_model, iis_file_name, solver, logger)\u001b[0m\n\u001b[0;32m 65\u001b[0m solver \u001b[38;5;241m=\u001b[39m _remove_suffix(solver, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m_persistent\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 66\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m solver \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m available_solvers:\n\u001b[1;32m---> 67\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mRuntimeError\u001b[39;00m(\n\u001b[0;32m 68\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mThe Pyomo persistent interface to \u001b[39m\u001b[38;5;132;01m{\u001b[39;00msolver\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m could not be found.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 69\u001b[0m )\n\u001b[0;32m 71\u001b[0m solver_name \u001b[38;5;241m=\u001b[39m solver\n\u001b[0;32m 72\u001b[0m solver \u001b[38;5;241m=\u001b[39m SolverFactory(solver \u001b[38;5;241m+\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m_persistent\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", + "\u001b[1;31mRuntimeError\u001b[0m: The Pyomo persistent interface to gurobi could not be found." + ] + } + ], + "source": [ + "import pyomo.contrib.iis\n", + "pyo.SolverFactory('gurobi_persistent')\n", + "pyomo.contrib.iis.write_iis(instance, \"Infeasibilities.ilp\", solver='gurobi')" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "path = \"../data/input/openMASTER_Data_2050_v1_Truck.xlsx\" #########RECORDAR CAMBIAR EL NOMBRE######\n", + "output_path = \"../data/tmp/output\"\n", + "sheetname = \"Output\"\n", + "\n", + "d_vars_from_instance = openMASTER.export_model_to_csv(path, output_path, sheetname, instance)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Loading variable information from .csv to a dictionary containing all outputs" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "d_vars = openMASTER.import_results_from_csv(output_path)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'sYear' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[22], line 9\u001b[0m\n\u001b[0;32m 6\u001b[0m duals_EQ_TEBalance \u001b[38;5;241m=\u001b[39m {}\n\u001b[0;32m 8\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m instance\u001b[38;5;241m.\u001b[39msYear:\n\u001b[1;32m----> 9\u001b[0m duals_EQ_TEBalance[\u001b[43msYear\u001b[49m] \u001b[38;5;241m=\u001b[39m {}\n\u001b[0;32m 10\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m j \u001b[38;5;129;01min\u001b[39;00m instance\u001b[38;5;241m.\u001b[39msSeason:\n\u001b[0;32m 11\u001b[0m duals_EQ_TEBalance[sYear][sSeason] \u001b[38;5;241m=\u001b[39m {}\n", + "\u001b[1;31mNameError\u001b[0m: name 'sYear' is not defined" + ] + } + ], + "source": [ + "# Lets make a dictionart with the dual values\n", + "# I want to access the dictionary in the following way duals_EQ_TEBalance[year][season][day]\n", + "# the results have to show a table for all technologies in rows and hours of the day in columns\n", + "# In this way I can easily access the dual values for all technology in the model for all hours of an specific year, season and day\n", + "\n", + "duals_EQ_TEBalance = {}\n", + "\n", + "for i in instance.sYear:\n", + " duals_EQ_TEBalance[sYear] = {}\n", + " for j in instance.sSeason:\n", + " duals_EQ_TEBalance[sYear][sSeason] = {}\n", + " for k in instance.sDay:\n", + " duals_EQ_TEBalance[sYear][sSeason][sDay] = {}\n", + " for l in instance.sHour:\n", + " duals_EQ_TEBalance[sYear][sSeason][sDay][sHour] = {}\n", + " for m in instance.sCEPri:\n", + " duals_EQ_TEBalance[sYear][sSeason][sDay][sHour][sTE] = instance.dual[instance.EQ_CEPriBalance[m,i,j,k,l]]\n", + "\n", + "\n", + "# Now build a dataframe with the dual values duals_EQ_TEBalance['y2020']['R']['d01'] for example with the dual values for all technologies in rows and hours of the day in columns" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'sYear' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[23], line 4\u001b[0m\n\u001b[0;32m 1\u001b[0m duals_EQ_TEBalance_sec \u001b[38;5;241m=\u001b[39m {}\n\u001b[0;32m 3\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m instance\u001b[38;5;241m.\u001b[39msYear:\n\u001b[1;32m----> 4\u001b[0m duals_EQ_TEBalance_sec[\u001b[43msYear\u001b[49m] \u001b[38;5;241m=\u001b[39m {}\n\u001b[0;32m 5\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m j \u001b[38;5;129;01min\u001b[39;00m instance\u001b[38;5;241m.\u001b[39msSeason:\n\u001b[0;32m 6\u001b[0m duals_EQ_TEBalance_sec[sYear][sSeason] \u001b[38;5;241m=\u001b[39m {}\n", + "\u001b[1;31mNameError\u001b[0m: name 'sYear' is not defined" + ] + } + ], + "source": [ + "duals_EQ_TEBalance_sec = {}\n", + "\n", + "for i in instance.sYear:\n", + " duals_EQ_TEBalance_sec[sYear] = {}\n", + " for j in instance.sSeason:\n", + " duals_EQ_TEBalance_sec[sYear][sSeason] = {}\n", + " for k in instance.sDay:\n", + " duals_EQ_TEBalance_sec[sYear][sSeason][sDay] = {}\n", + " for l in instance.sHour:\n", + " duals_EQ_TEBalance_sec[sYear][sSeason][sDay][sHour] = {}\n", + " for m in instance.sCESec:\n", + " duals_EQ_TEBalance_sec[sYear][sSeason][sDay][sHour][sTE] = instance.dual[instance.EQ_CESecBalance[m,i,j,k,l]]" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "ename": "KeyError", + "evalue": "'y2025'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[18], line 4\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mpandas\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01mpd\u001b[39;00m\n\u001b[0;32m 2\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mnumpy\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01mnp\u001b[39;00m\n\u001b[1;32m----> 4\u001b[0m df_1 \u001b[38;5;241m=\u001b[39m pd\u001b[38;5;241m.\u001b[39mDataFrame(\u001b[43mduals_EQ_TEBalance\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43my2025\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mR\u001b[39m\u001b[38;5;124m'\u001b[39m][\u001b[38;5;124m'\u001b[39m\u001b[38;5;124md01\u001b[39m\u001b[38;5;124m'\u001b[39m])\u001b[38;5;241m.\u001b[39mdrop([\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCEBIODIEPP\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCEBIOETHPP\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCEREFINLOWC\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCEREFINHIGC\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCEREFINVHIC\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCEREGASIF\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msPE2TE_IMCO\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msPE2TE_NAGAS\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msPE2TE_BIOMA\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCESOPHVDIWOTIND\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCESOPHVDIWOTOTH\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCESOLTHDIIND\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCESOLTHDIOTH\u001b[39m\u001b[38;5;124m'\u001b[39m])\n\u001b[0;32m 5\u001b[0m df_2 \u001b[38;5;241m=\u001b[39m pd\u001b[38;5;241m.\u001b[39mDataFrame(duals_EQ_TEBalance[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124my2025\u001b[39m\u001b[38;5;124m'\u001b[39m][\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mS\u001b[39m\u001b[38;5;124m'\u001b[39m][\u001b[38;5;124m'\u001b[39m\u001b[38;5;124md01\u001b[39m\u001b[38;5;124m'\u001b[39m])\u001b[38;5;241m.\u001b[39mdrop([\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCEBIODIEPP\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCEBIOETHPP\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCEREFINLOWC\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCEREFINHIGC\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCEREFINVHIC\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCEREGASIF\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msPE2TE_IMCO\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msPE2TE_NAGAS\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msPE2TE_BIOMA\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCESOPHVDIWOTIND\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCESOPHVDIWOTOTH\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCESOLTHDIIND\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCESOLTHDIOTH\u001b[39m\u001b[38;5;124m'\u001b[39m])\n\u001b[0;32m 6\u001b[0m df_3 \u001b[38;5;241m=\u001b[39m pd\u001b[38;5;241m.\u001b[39mDataFrame(duals_EQ_TEBalance[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124my2025\u001b[39m\u001b[38;5;124m'\u001b[39m][\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mF\u001b[39m\u001b[38;5;124m'\u001b[39m][\u001b[38;5;124m'\u001b[39m\u001b[38;5;124md01\u001b[39m\u001b[38;5;124m'\u001b[39m])\u001b[38;5;241m.\u001b[39mdrop([\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCEBIODIEPP\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCEBIOETHPP\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCEREFINLOWC\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCEREFINHIGC\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCEREFINVHIC\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCEREGASIF\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msPE2TE_IMCO\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msPE2TE_NAGAS\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msPE2TE_BIOMA\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCESOPHVDIWOTIND\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCESOPHVDIWOTOTH\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCESOLTHDIIND\u001b[39m\u001b[38;5;124m'\u001b[39m,\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msCESOLTHDIOTH\u001b[39m\u001b[38;5;124m'\u001b[39m])\n", + "\u001b[1;31mKeyError\u001b[0m: 'y2025'" + ] + } + ], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "df_1 = pd.DataFrame(duals_EQ_TEBalance['y2025']['R']['d01']).drop(['sCEBIODIEPP','sCEBIOETHPP','sCEREFINLOWC','sCEREFINHIGC','sCEREFINVHIC','sCEREGASIF','sPE2TE_IMCO','sPE2TE_NAGAS','sPE2TE_BIOMA','sCESOPHVDIWOTIND','sCESOPHVDIWOTOTH','sCESOLTHDIIND','sCESOLTHDIOTH'])\n", + "df_2 = pd.DataFrame(duals_EQ_TEBalance['y2025']['S']['d01']).drop(['sCEBIODIEPP','sCEBIOETHPP','sCEREFINLOWC','sCEREFINHIGC','sCEREFINVHIC','sCEREGASIF','sPE2TE_IMCO','sPE2TE_NAGAS','sPE2TE_BIOMA','sCESOPHVDIWOTIND','sCESOPHVDIWOTOTH','sCESOLTHDIIND','sCESOLTHDIOTH'])\n", + "df_3 = pd.DataFrame(duals_EQ_TEBalance['y2025']['F']['d01']).drop(['sCEBIODIEPP','sCEBIOETHPP','sCEREFINLOWC','sCEREFINHIGC','sCEREFINVHIC','sCEREGASIF','sPE2TE_IMCO','sPE2TE_NAGAS','sPE2TE_BIOMA','sCESOPHVDIWOTIND','sCESOPHVDIWOTOTH','sCESOLTHDIIND','sCESOLTHDIOTH'])\n", + "df_4 = pd.DataFrame(duals_EQ_TEBalance['y2025']['W']['d01']).drop(['sCEBIODIEPP','sCEBIOETHPP','sCEREFINLOWC','sCEREFINHIGC','sCEREFINVHIC','sCEREGASIF','sPE2TE_IMCO','sPE2TE_NAGAS','sPE2TE_BIOMA','sCESOPHVDIWOTIND','sCESOPHVDIWOTOTH','sCESOLTHDIIND','sCESOLTHDIOTH'])\n", + "\n", + "df1_sec = pd.DataFrame(duals_EQ_TEBalance_sec['y2020']['R']['d01']).iloc[0:4,:]\n", + "\n", + "# Graph the results in a temporal line. In the x axis first put the values of hours of the df_1, then the values of df_2, then df_3 and finally df_4\n", + "# The y axis should be the dual values\n", + "# The graph should have as plots as technologies in the model (rows of the dfs)\n", + "\n", + "import matplotlib.pyplot as plt\n", + "\n", + "#plt.plot(df_1.T)\n", + "\n", + "# Change the colors for different technologies\n", + "colors = plt.cm.viridis(np.linspace(0, 1, len(df_1.index)))\n", + "for i, color in enumerate(colors):\n", + " plt.plot(df_1.T.index, df_1.T.iloc[:,i]*1000, color=color)\n", + " # plt.plot(df1_sec.T*1000) \n", + "\n", + "\n", + "#plt.legend(df_1.index)\n", + "plt.legend(df_1.index)\n", + "# Take the legend out of the plot\n", + "plt.legend(df_1.index, bbox_to_anchor=(1.05, 1), loc='upper left')\n", + "# plt.legend(df1_sec.index, bbox_to_anchor=(1.05, 1), loc='upper left') \n", + "plt.ylabel('Dual values [€/kWh]')\n", + "# Rotate the x axis labels\n", + "plt.xticks(rotation=90)\n", + "plt.xlabel('Hours of the day')\n", + "plt.title('Dual values for each sCEPri technology in the model for year 2020, season R and day 01')\n", + "plt.grid()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'df_4' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[12], line 3\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;66;03m# lets calculate the mean of each row of df_1\u001b[39;00m\n\u001b[1;32m----> 3\u001b[0m \u001b[43mdf_4\u001b[49m\u001b[38;5;241m.\u001b[39mmean(axis\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m1\u001b[39m)\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m1000\u001b[39m\n", + "\u001b[1;31mNameError\u001b[0m: name 'df_4' is not defined" + ] + } + ], + "source": [ + "# lets calculate the mean of each row of df_1\n", + "\n", + "df_4.mean(axis=1)*1000\n" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'plt' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[19], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[43mplt\u001b[49m\u001b[38;5;241m.\u001b[39mplot(df1_sec\u001b[38;5;241m.\u001b[39mT\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m1000\u001b[39m) \n\u001b[0;32m 2\u001b[0m plt\u001b[38;5;241m.\u001b[39mlegend(df1_sec\u001b[38;5;241m.\u001b[39mindex) \n\u001b[0;32m 3\u001b[0m plt\u001b[38;5;241m.\u001b[39mlegend(df1_sec\u001b[38;5;241m.\u001b[39mindex, bbox_to_anchor\u001b[38;5;241m=\u001b[39m(\u001b[38;5;241m1.05\u001b[39m, \u001b[38;5;241m1\u001b[39m), loc\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mupper left\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", + "\u001b[1;31mNameError\u001b[0m: name 'plt' is not defined" + ] + } + ], + "source": [ + "plt.plot(df1_sec.T*1000) \n", + "plt.legend(df1_sec.index) \n", + "plt.legend(df1_sec.index, bbox_to_anchor=(1.05, 1), loc='upper left')\n", + "plt.ylabel('Dual values [€/kWh]')\n", + "plt.xticks(rotation=90)\n", + "plt.xlabel('Hours of the day')\n", + "plt.title('Dual values for each sCESec technology in the model for year 2020, season R and day 01')\n", + "plt.grid()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "# Lets make a dictionart with the dual values\n", + "# I want to access the dictionary in the following way duals[year][season][day]\n", + "# the results have to show a table for all technologies in rows and hours of the day in columns\n", + "# In this way I can easily access the dual values for all technology in the model for all hours of an specific year, season and day\n", + "\n", + "duals_EQ_TEBalance = {}\n", + "for m in instance.sTE:\n", + " duals_EQ_TEBalance[m] = {}\n", + " for i in instance.sYear:\n", + " duals_EQ_TEBalance[m][i] = {}\n", + " for j in instance.sSeason:\n", + " duals_EQ_TEBalance[m][i][j] = {}\n", + " for k in instance.sDay:\n", + " duals_EQ_TEBalance[m][i][j][k] = {}\n", + " for l in instance.sHour:\n", + " duals_EQ_TEBalance[m][i][j][k][l] = instance.dual[instance.EQ_TEBalance[m,i,j,k,l]]\n", + " \n", + "\n", + "import csv\n", + "\n", + "# Assuming duals_EQ_TEBalance is populated as per your code above\n", + "\n", + "# Open a new CSV file to write into\n", + "with open('../data/tmp/output/duals_EQ_TEBalance.csv', 'w', newline='') as file:\n", + " writer = csv.writer(file)\n", + " \n", + " # Write the header of the CSV file\n", + " writer.writerow(['sTE', 'sYear', 'sSeason', 'sDay', 'sHour', 'dual_value'])\n", + " \n", + " # Iterate through each level of the dictionary to write rows\n", + " for m in duals_EQ_TEBalance:\n", + " for i in duals_EQ_TEBalance[m]:\n", + " for j in duals_EQ_TEBalance[m][i]:\n", + " for k in duals_EQ_TEBalance[m][i][j]:\n", + " for l in duals_EQ_TEBalance[m][i][j][k]:\n", + " # Retrieve the dual value for the current combination of indices\n", + " dual_value = duals_EQ_TEBalance[m][i][j][k][l]\n", + " # Write the current row to the CSV file\n", + " writer.writerow([m, i, j, k, l, dual_value])\n", + "\n", + "\n", + "# Convert duals['sTEELECE']['y2020']['R']['d01'] to a dataframe with the dual values for all hours of the day\n", + "\n", + "#Lets calculate the consumption\n", + "# consumption = {}\n", + "# for m in instance.sTE:\n", + "# consumption[m] = {}\n", + "# for i in instance.sST:\n", + "# consumption[m][i] = {}\n", + "# for j in instance.sES:\n", + "# consumption[m][i][j] = {}\n", + "# for k in instance.sVin:\n", + "# consumption[m][i][j][k] = {}\n", + "# for l in instance.sYear:\n", + "# consumption[m][i][j][k][l] = {}\n", + "# for n in instance.sSeason:\n", + "# consumption[m][i][j][k][l][n] = {}\n", + "# for o in instance.sDay:\n", + "# consumption[m][i][j][k][l][n][o] = {}\n", + "# for p in instance.sHour:\n", + "# consumption[m][i][j][k][l][n][o][p] = instance.vQSTInTE[m,i,j,k,l,n,o,p].value for [m,i,j] in instance.sQTESTES_Ele" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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0t9b3bp18cYbb8BgMFicZ+//i86dOxeqRHbu3BlBQUE4c+aMdCwlJQV79+7FiBEjpMQGAEaNGgWdTocvvvhCOtahQ4dCSV/9+vXRtGlTizYB4Msvv0S/fv2kxAYAevTogQYNGli06W5YuXETI0eOxKuvvooff/wREyZMsPv+7733Hvr374/hw4dDr9fj888/x+DBg7F792707dvX5nY8PT3x2GOPYceOHfjwww8t/gB27tyJ7OxsDBs2DIDpj+mTTz7BE088gQkTJiA1NRVr1qxBZGQkjhw5glatWtn9PKx58803MWvWLAwZMgRPPfUUbt68ieXLl6Nz5874888/ERAQAL1ej8jISGRnZ+O5555DaGgorl27ht27dyMpKQn+/v5W2162bBk+/fRTfPXVV/jggw+g0+mkrsG5c+di3rx56NGjB5555hmcO3cOH3zwAX7//XccPHjQoovl9u3b6NOnD4YNG4YRI0YgJCSkyOdz6tQpdOzYEdWrV8crr7wCHx8ffPHFFxgwYAC+/PJLPPbYY0Xed//+/ejTpw8iIiIwZ84cKJVKrFu3Dt27d8eBAwfQtm1bAEBcXBzatm2LpKQkPP3002jUqBGuXbuG7du3IyMjA507d8aUKVPw/vvv49VXX0Xjxo0BQPoMmLp3nnjiCUycOBETJkxAw4YNrcaUlpaGTp064cyZMxg3bhzuu+8+3Lp1C7t27cLVq1dRuXLlQveZOHEi4uLisHfvXmzcuFE6rlAoMGLECCxatAh37txBUFCQdNs333yDlJQUjBgxosifT3Gee+45BAYGYs6cObh48SKWLVuGyZMnY+vWrUXep6g489uyZQtSU1MxceJEKBQKLFq0CI8//jj+++8/6Rpx5ndutnnzZuj1ejz33HO4c+cOFi1ahCFDhqB79+6IiYnBjBkz8M8//2D58uV46aWXsHbtWum+tl7La9aswcSJE9GhQwdMnToV//33H/r374+goCDUrFlTas9oNKJ///745Zdf8PTTT6Nx48Y4ceIE3n33XZw/fx47d+605VcCwHTNbdy4ES+88AJq1KiBF198EYDpzUZmZia6du2Kf/75B5MnT0Z4eDi2bduGMWPGICkpCc8//7xFW+vWrUNWVhaefvppaDQai+snv5EjR2LChAk4efKkRRfM77//jvPnz+O1116Tjk2cOBHr16/H2LFj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LL5YuXJl7Nu3D5GRkXj44YfxySef2ByX3O25c2yyKvN0qpx49tlnRe3atcWOHTssltFPTk4WO3bsEGFhYWLy5MkuaY+xuUd77hyb3O117dq12D2Ljh8/btf+TXK2586xyd0eY3OP9ho2bCi+/fbbQsdTU1NF+/btRcuWLe2qZsjZnjvHJicmNw7KysoS//d//yct8qbVaoVWqxVKpVKo1WrxzDPP2LUTtJztMTb3aM+dY5O7vY8++ki89957Rd5+48aNYhflK8323Dk2udtjbO7R3nPPPVfkBrspKSmiXbt2dr3gy9meO8cmJ65z46SUlBQcPXrUYhptRESExR4lrmqPsblHe+4cW2m0R1TRJSYmIi4uDk2bNrV6e2pqKo4dO4YuXbqUeXvuHJucmNzIICoqClFRUUhISCi0OeDatWtd2h5jc4/23Dk2udtjbO7RHmNzj/YYm+PtOYMDip00b948vP7662jTpg2qVq0q7cjrDu0xNvdoz51jk7s9xuYe7TE292iPsblQmXeElTOhoaHi008/dcv2GJt7tOfOscndHmNzj/YYm3u0x9hcxzU7d5Ujer0eHTp0cMv2GJt7tOfOscndHmNzj/YYm3u0x9hch8mNk5566ils2bLFLdtjbO7RnjvHJnd7jM092mNs7tEeY3MdDih2wLRp06SvjUYjNmzYgBYtWqBFixbw9PS0OHfp0qVl2h5jc4/23Dk2udtjbO7RHmNzj/YYm+PtyYnJjQO6detm03kKhQL79+8v0/YYm3u0586xyd0eY3OP9hibe7TH2BxvT05MboiIiKhc4ZgbIiIiKleY3BAREVG5wuSGiIiIyhUmN0RERFSuMLkhonvezp07Ua9ePahUKkydOtXm+82dOxetWrUqtbjyCwsLw7Jly8rksYgqOiY3RBXImDFjMGDAgELHY2JioFAokJSUVOYxyWHixIkYNGgQrly5gjfeeMPqOQqFAjt37izbwIjIJbhxJhGVmZycnEKLezkrLS0NCQkJiIyMRLVq1WRtm4juTazcEJFVX375JZo2bQqNRoOwsDAsWbLE4nZrlZCAgACsX78eAHDx4kUoFAps3boVXbp0gVarxebNm3Hp0iU88sgjCAwMhI+PD5o2bYrvvvuuyDgSExMxatQoBAYGwtvbG3369MGFCxcAmCpOvr6+AIDu3btDoVAgJiamUBthYWEAgMceewwKhUL63mzjxo0ICwuDv78/hg0bhtTUVOk2o9GIBQsWIDw8HF5eXmjZsiW2b99e7M8uISEBjzzyCLy8vBAeHo7NmzcXOmfp0qVo3rw5fHx8ULNmTTz77LNIS0sDAKSnp8PPz6/Q4+zcuRM+Pj4W8RFRYUxuiKiQo0ePYsiQIRg2bBhOnDiBuXPnYtasWVLiYo9XXnkFzz//PM6cOYPIyEhMmjQJ2dnZ+Pnnn3HixAksXLgQOp2uyPuPGTMGf/zxB3bt2oVDhw5BCIGHH34YOTk56NChA86dOwfAlIxdv37d6uZ9v//+OwBg3bp1uH79uvQ9APz777/YuXMndu/ejd27d+Onn37C22+/Ld2+YMECfPrpp1i9ejVOnTqFF154ASNGjMBPP/1UbMxXrlxBdHQ0tm/fjlWrViEhIcHiHKVSiffffx+nTp3Chg0bsH//frz88ssAAB8fHwwbNgzr1q2zuM+6deswaNAgKaEjoiK4cEdyIipjo0ePFiqVSvj4+Fh8aLVaAUAkJiYKIYR48sknRc+ePS3uO336dNGkSRPpewDiq6++sjjH399frFu3TgghRGxsrAAgli1bZnFO8+bNxdy5c22K9/z58wKAOHjwoHTs1q1bwsvLS3zxxRdCCCESExMFABEdHV1sW9binTNnjvD29hYpKSkWz7Ndu3ZCCCGysrKEt7e3+PXXXy3uN378ePHEE09YfZxz584JAOLIkSPSsTNnzggA4t133y0yvm3btolKlSpJ3x8+fFioVCoRFxcnhBAiPj5eeHh4iJiYmGKfJxEJwcoNUQXTrVs3HD9+3OLjk08+sTjnzJkz6Nixo8Wxjh074sKFCzAYDHY9Xps2bSy+nzJlCubPn4+OHTtizpw5+Pvvv4u875kzZ+Dh4YF27dpJxypVqoSGDRvizJkzdsVRlLCwMItKSNWqVaUqyz///IOMjAz07NkTOp1O+vj000/x77//FhtzRESEdKxRo0YICAiwOG/fvn146KGHUL16dfj6+mLkyJG4ffs2MjIyAABt27ZF06ZNsWHDBgDApk2bULt2bXTu3FmW501UnjG5IapgfHx8UK9ePYuP6tWr292OQqGAKLA1XU5OjtXHy++pp57Cf//9h5EjR+LEiRNo06YNli9fbvfjy6XgAGeFQgGj0QgA0hiYb7/91iIZPH36dInjbopz8eJF9OvXDy1atMCXX36Jo0ePYuXKlQAAvV4vnffUU09JXYHr1q3D2LFjoVAoHH5cooqCyQ0RFdK4cWMcPHjQ4tjBgwfRoEEDqFQqAECVKlVw/fp16fYLFy5IVYeS1KxZE//3f/+HHTt24MUXX8THH39cZBy5ubk4fPiwdOz27ds4d+4cmjRpYtdz8vT0tLvq1KRJE2g0Gly+fLlQQlizZk2r92nUqBFyc3Nx9OhR6di5c+csptkfPXoURqMRS5YswQMPPIAGDRogLi6uUFsjRozApUuX8P777+P06dMYPXq0XfETVVScCk5Ehbz44ou4//778cYbb2Do0KE4dOgQVqxYgVWrVknndO/eHStWrED79u1hMBgwY8YMm6Z5T506FX369EGDBg2QmJiI6OhoNG7c2Oq59evXx6OPPooJEybgww8/hK+vL1555RVUr14djz76qF3PKSwsDFFRUejYsSM0Gg0CAwNLvI+vry9eeuklvPDCCzAajXjwwQeRnJyMgwcPws/Pz2qy0bBhQ/Tu3RsTJ07EBx98AA8PD0ydOhVeXl7SOfXq1UNOTg6WL1+ORx55BAcPHsTq1asLtRUYGIjHH38c06dPR69evVCjRg27njNRRcXKDREVct999+GLL77A559/jmbNmmH27Nl4/fXXMWbMGOmcJUuWoGbNmujUqROefPJJvPTSS/D29i6xbYPBgEmTJqFx48bo3bs3GjRoYJE0FbRu3TpERESgX79+aN++PYQQ+O677+xeL2fJkiXYu3cvatasidatW9t8vzfeeAOzZs3CggULpJi//fZbhIeHFxtztWrV0KVLFzz++ON4+umnERwcLN3esmVLLF26FAsXLkSzZs2wefNmLFiwwGpb48ePh16vx7hx42x/skQVnEIU7DQnIiK3sXHjRrzwwguIi4uDWq12dThE9wR2SxERuaGMjAxcv34db7/9NiZOnMjEhsgO7JYiInJDixYtQqNGjRAaGoqZM2e6Ohyiewq7pYiIiKhcYeWGiIiIyhUmN0RERFSuMLkhIiKicoXJDREREZUrTG6IiIioXGFyQ0REROUKkxsiIiIqV5jcEBERUbny/9D4FrC2ovNSAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import pandas as pd\n", + "\n", + "df_summer = pd.DataFrame.from_dict(duals_EQ_TEBalance['sTEELECE']['y2020']['R']['d01'], orient='index', columns=['Value'])*1000\n", + "df_spring = pd.DataFrame.from_dict(duals_EQ_TEBalance['sTEELECE']['y2020']['S']['d01'], orient='index', columns=['Value'])*1000\n", + "df_autumn = pd.DataFrame.from_dict(duals_EQ_TEBalance['sTEELECE']['y2020']['F']['d01'], orient='index', columns=['Value'])*1000\n", + "df_winter = pd.DataFrame.from_dict(duals_EQ_TEBalance['sTEELECE']['y2020']['W']['d01'], orient='index', columns=['Value'])*1000\n", + "\n", + "# Graph the results in a temporal line. In the x axis first put the values of hours of the df_1, then the values of df_2, then df_3 and finally df_4\n", + "# The y axis should be the dual values\n", + "# The graph should have as plots as technologies in the model (rows of the dfs)\n", + "\n", + "import matplotlib.pyplot as plt\n", + "\n", + "plt.plot(df_summer)\n", + "plt.plot(df_spring)\n", + "plt.plot(df_autumn)\n", + "# plt.plot(df_winter)\n", + "\n", + "# rotate the x axis labels\n", + "plt.xticks(rotation=90)\n", + "plt.ylabel('[€/kWh]')\n", + "plt.xlabel('Hours of the day')\n", + "plt.title('Dual values for electricity in the model for year 2020')\n", + "plt.legend(['Summer', 'Spring', 'Autumn', 'Winter'])\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "ename": "KeyError", + "evalue": "'y2020'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[26], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m df_1 \u001b[38;5;241m=\u001b[39m pd\u001b[38;5;241m.\u001b[39mDataFrame(\u001b[43mduals_EQ_TEBalance\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43my2020\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mR\u001b[39m\u001b[38;5;124m'\u001b[39m][\u001b[38;5;124m'\u001b[39m\u001b[38;5;124md01\u001b[39m\u001b[38;5;124m'\u001b[39m])\n\u001b[0;32m 2\u001b[0m df_2 \u001b[38;5;241m=\u001b[39m pd\u001b[38;5;241m.\u001b[39mDataFrame(duals_EQ_TEBalance[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124my2020\u001b[39m\u001b[38;5;124m'\u001b[39m][\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mS\u001b[39m\u001b[38;5;124m'\u001b[39m][\u001b[38;5;124m'\u001b[39m\u001b[38;5;124md01\u001b[39m\u001b[38;5;124m'\u001b[39m])\n\u001b[0;32m 3\u001b[0m df_3 \u001b[38;5;241m=\u001b[39m pd\u001b[38;5;241m.\u001b[39mDataFrame(duals_EQ_TEBalance[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124my2020\u001b[39m\u001b[38;5;124m'\u001b[39m][\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mF\u001b[39m\u001b[38;5;124m'\u001b[39m][\u001b[38;5;124m'\u001b[39m\u001b[38;5;124md01\u001b[39m\u001b[38;5;124m'\u001b[39m])\n", + "\u001b[1;31mKeyError\u001b[0m: 'y2020'" + ] + } + ], + "source": [ + "df_1 = pd.DataFrame(duals_EQ_TEBalance['y2020']['R']['d01'])\n", + "df_2 = pd.DataFrame(duals_EQ_TEBalance['y2020']['S']['d01'])\n", + "df_3 = pd.DataFrame(duals_EQ_TEBalance['y2020']['F']['d01'])\n", + "# df_4 = pd.DataFrame(duals_EQ_TEBalance['y2020']['W']['d01'])\n", + "\n", + "# preserve only the values for the rows DIFFERENT to sTEH2\n", + "#df_4 = df_4.drop(['sTEH2','sTEELEDIIND'])\n", + "\n", + "#PRESERVE ONLY sTEELECE in df_1\n", + "df_1 = df_1.iloc[0:1,:]*1000\n", + "df_2 = df_2.iloc[0:1,:]*1000\n", + "df_3 = df_3.iloc[0:1,:]*1000\n", + "# df_4 = df_4.iloc[0:1,:]*1000\n", + "\n", + "# State the mean value for the whole year duals_EQ_TEBalance = df_1.mean(axis=0)\n", + "\n", + "df_1_mean = df_1.mean(axis=1)\n", + "df_2_mean = df_2.mean(axis=1)\n", + "df_3_mean = df_3.mean(axis=1)\n", + "# df_4_mean = df_4.mean(axis=1)\n", + "\n", + "# Considering that each df corresponds to a season of the year, establish the mean value for the whole year\n", + "df_mean = pd.concat([df_1_mean,df_2_mean,df_3_mean],axis=1)\n", + "\n", + "# Graph the results in a temporal line. In the x axis first put the values of hours of the df_1, then the values of df_2, then df_3 and finally df_4\n", + "# The y axis should be the dual values\n", + "# The graph should have as plots as technologies in the model (rows of the dfs)\n", + "\n", + "import matplotlib.pyplot as plt\n", + "\n", + "#plt.plot(df_1.T)\n", + "\n", + "# Change the colors for different technologies\n", + "colors = plt.cm.viridis(np.linspace(0, 1, len(df_1.index)))\n", + "for i, color in enumerate(colors):\n", + " plt.plot(df_1.T.index, df_1.T.iloc[:,i], color='red')\n", + " plt.plot(df_2.T.index, df_2.T.iloc[:,i], color='lightblue')\n", + " plt.plot(df_3.T.index, df_3.T.iloc[:,i], color='blue')\n", + " # plt.plot(df_4.T.index, df_4.T.iloc[:,i], color='orange')\n", + "\n", + "\n", + "plt.legend(['Summer','Spring','Fall'])\n", + "# Take the legend out of the plot\n", + "plt.legend(['Summer','Spring','Fall'],bbox_to_anchor=(1.05, 1), loc='upper left')\n", + "plt.ylabel('Dual values [€/kWh]')\n", + "# Rotate the x axis labels\n", + "plt.xticks(rotation=90)\n", + "plt.xlabel('Hours of the day')\n", + "plt.title('Dual values for each Electricity for year 2020 in a representative day')\n", + "plt.grid()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [], + "source": [ + "dual_values = []\n", + "consumptions = []\n", + "\n", + "for sSeason in instance.sSeason:\n", + " for sDay in instance.sDay:\n", + " for sHour in instance.sHour:\n", + " try:\n", + " dual_value = instance.dual[instance.EQ_TEBalance['sTEELECE', 'y2030', sSeason, sDay, sHour]]\n", + " consumption = sum(instance.vQSTInTE[sTE, sST, sES, sVin, 'y2030', sSeason, sDay, sHour].value\n", + " for (sTE, sST, sES) in instance.sQTESTES_Ele if sTE in instance.sTE_Ele\n", + " for sVin in instance.sVin if (sVin, 'y2030') in instance.sVinYear)\n", + " dual_values.append(dual_value)\n", + " consumptions.append(consumption)\n", + " except KeyError:\n", + " print(f\"No dual value for EQ_TEBalance['sTEELECE', 'y2030', {sSeason}, {sDay}, {sHour}]\")\n", + "\n", + "total_consumption = sum(consumptions)\n", + "weighted_sum_dual_values = sum(dual * consumption for dual, consumption in zip(dual_values, consumptions))\n", + "electricity_affordability_2030 = weighted_sum_dual_values / total_consumption if total_consumption != 0 else 0" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.0002764220568741964" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "electricity_affordability_2030" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: total: 4min 5s\n", - "Wall time: 4min 8s\n" + "Total_GWh_Households_TEST: 168829.2250326372\n", + "Total_GWh_Industry: 231552.63130958058\n", + "Total_GWh_Transport: 220575.60689743026\n", + "Total_GWh_Services: 87412.87107867762\n", + "Energy Service Not Served for the calibration year: 0.0\n" + ] + } + ], + "source": [ + "# Total Consumption by Sector\n", + "# Show all the rows in the df d_vars['vQES'] that include in the column sES the value 'sES_DSOTH_RES' at the begining of the string and that the value in sYear is y2020\n", + "#Total_GWh_Households_ESSD = d_vars['vQES'][(d_vars['vQES'].sES.str.startswith('sES_DSOTH_RES')) & (d_vars['vQES'].sYear=='y2020')].vQES.sum() # Calibracion en ES consumido por SDMD\n", + "Total_GWh_Households_TEST = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sYear == 'y2020') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum() # Calibracion en TE consumida por ST \n", + "Total_GWh_Industry = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sYear == 'y2020') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSIND'))].vQSTInTE.sum()\n", + "Total_GWh_Transport = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sYear == 'y2020') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "Total_GWh_Services = d_vars['vQES'][(d_vars['vQES'].sES.str.startswith('sES_DSOTH_SRV')) & (d_vars['vQES'].sYear=='y2020')].vQES.sum()\n", + "\n", + "ES_NS = d_vars['vQESNS'][(d_vars['vQESNS'].sYear=='y2020')].vQESNS.sum()\n", + "\n", + "\n", + "\n", + "#print(f\"Total_GWh_Households_ESSD: {Total_GWh_Households_ESSD }\")\n", + "print(f\"Total_GWh_Households_TEST: {Total_GWh_Households_TEST }\")\n", + "print(f\"Total_GWh_Industry: {Total_GWh_Industry }\")\n", + "print(f\"Total_GWh_Transport: {Total_GWh_Transport }\")\n", + "print(f\"Total_GWh_Services: {Total_GWh_Services }\")\n", + "print(f\"Energy Service Not Served for the calibration year: {ES_NS}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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jbi5udGyZUtat26Nn58fa9eufeR5lyxZQnR0NPXr16dfv3689dZblCpVKl9j//DDD3n33XeZOXMm1apVo127dmzduhVfX998vQ6Y5iP+/PPPHDlyhDp16jB8+HCGDBnC1KlTnzie2rVrExoayt9//02LFi2oV68e7733Hs8//7zaZsGCBbz22muMHDmSqlWrMmzYMLXkc5kyZXj//feZPHkypUuXNqua9jg2Njbs3LmTUqVK0aFDB2rVqsXHH3+sfkb873//w83NjWbNmtG5c2eCg4OpX7/+k7x02WgUC/4MtXnzZnQ6HZUqVUJRFFasWMF///tf/vjjD2rUqMGIESPYunUry5cvx8XFhdGjR6PVatWVaA0GA3Xr1sXLy4v//ve/REZG0r9/f4YNG8aMGTMACAsLo2bNmgwfPpyhQ4eye/duxo4dy9atW9X62mvXrqV///4sXLiQJk2aMGfOHNavX8/58+fV/6M8LpbciIuLw8XFhdjYWJydnfP51RRCFHexO68QvycC+7rP4d6rqqXDeazMxSs7d+782Mmjxc2BAwfYuXMnAL169aJq1aL/30MUHEt/fqekpBAWFoavry+2traFfn0hLCm3f/8WTWpy4u7uzn//+19ee+01nnvuOVavXq3+anbu3DmqVavGwYMHadq0Kdu2baNTp07cuHFDrSaxcOFCJk2axJ07d7CxsWHSpEls3bqVv/76S71Gr169iImJYfv27QA0adKERo0aqb8cGI1GfHx8GDNmDJMnTyY2NvaxseSGpd8UhRBFW8rFGO4uPoXO2QavKY2L9Lya5ORkZs2ahaIojB07FldXV0uHlK8URWHLli0cO3YMa2trBg8ejLe3t6XDEhZi6c9vSWrEsyy3f/9FZk6NwWBgzZo1JCYmEhAQwLFjx0hPTzebwFS1alXKlSunDgc4ePAgtWrVUhMagODgYOLi4jh9+rTa5uFJUMHBweo50tLSOHbsmFkbrVZL69at1Ta5iSUnqampxMXFmW1CCPEoNuWcTPNq4tIwRBXteTWXL19GURQ8PT1LXEIDpmExHTp0wM/Pj/T0dFavXi3v4UIIUYRZPKk5deoUjo6O6PV6hg8fzk8//UT16tW5efMmNjY22T4sS5cuzc2bNwG4efOmWUKTeTzz2D+1iYuLIzk5mbt372IwGHJsk/Ucj4slJzNnzsTFxUXd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n76iCyDzakTetWrVCldXV+Li4tizZ88TnSMiNoLPDn5GsyXNKDenHON3jufQtUPq0LIv2n/B9fHXCR0YyujGoyWhEbly5coVNBoNJ06ceGSbkJAQNBoNMTExhRbX01AUhX79+qEoillCs3z5crMf1adPn66OmnqUgQMH8sorrxRMoEVQnko6jxw5krS0NMqXL09QUJC6lSlT5okuPmrUKFavXs3GjRtxcnJS56a4uLhgZ2eHi4sLQ4YMYfz48bi7u+Ps7MyYMWMICAhQq421bduW6tWr069fP2bNmsXNmzeZOnUqo0aNUn9NGj58OPPmzePtt99m8ODB7Nmzh3Xr1rF161Y1lvHjxzNgwAAaNmxI48aNmTNnDomJiQwaNEiN6XGxCCFE/sgA1mLqmTl9f58tMBSYAJR/5DMNBgOXL18GMKtQKfNqxJOysbGhU6dOrFy5ksOHD1OrVi2zURWPktkjs/7Meg5ee1BQR4OGF8q9oFYte95Jeg5LqoEDB7JixQoArKysKFu2LN27d+eDDz7IlypuPj4+REZGFvnejKSkJD788EPWrVvH9evXcXJyonr16owfP54uXbqYtZ0xYwZeXl5Mnz79H885YcIExowZU4BRFz95SmpiYmI4cOAAoaGh7N27l9WrV5OWloa/v7+a4LRq1SrbhPtHWbBgAWD6FSirZcuWMXDgQAA+++wztFot3bp1IzU1leDgYObPn6+21el0bNmyhREjRhAQEICDgwMDBgzggw8+UNv4+vqydetWxo0bx9y5cylbtiyLFy9W16gB6NmzJ3fu3OG9997j5s2b1K1bl+3bt5vdy+NisRSjMZW0tHvY2sovW0IUbynAckxVzMLu73PGVN3sX8Dj31uvX79Oamoqtra2Zj84ybwa8TT8/f2pVasWp06dYvPmzbzxxhvodLps7a7FXTMNLTu9LsdEpnv17nSr3k0SmWdIu3btWLZsGenp6Rw7dowBAwag0Wj45JNPnvrcOp3ukVMAipLhw4dz+PBhvvjiC6pXr05UVBQHDhwgKioqW9v/+7//y9U5HR0dcXR0zO9QizflKSQnJyt79uxR3n33XaVFixaKra2totPpnuaUJVpsbKwCKLGxsfl63vDw5cqevVWVv//+SElNjcrXcwshCkOcoiizFEXxUhSF+9tziqLMUBQlJk9n2r17tzJt2jRl3bp1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4MCBA8jJycGwYcMU8ydOnAgvLy9kZ2cby0pKSnD16lUkJCQYy4qKivDUU0/h1Vdfxfr16y3Wk5CQoGgDAI4ePapoo69zVqysyc/Px5AhQ+yzIU5gr1iZk2UZAIw7CBxXtsfKGncbV4B94pWVlYWCggLk5+cjPz/feJje8ePHkZKSAoBjqyexssbdxpaj/g7z8/MxcOBA+Pj4APCMcUVEZlx3jQIytWjRIjFgwACRl5enuARlY2Ojsc7ChQtFVFSUyMnJEWfOnBEJCQkiISHBOL+wsFCEhISIefPmKdqorq421um4jOWKFStEcXGx2LZtm9tdxtJZsdq0aZM4ePCguHz5sigsLBTLli0TKpVKHDt2zKnb2xv2iNWhQ4fErl27RGFhoSgrKxOff/65iI2NFYmJicY6HFcGtsTKE8aVEPaJlzlrV+/i2LLOWqw8YWzZI1afffaZyMzMFIWFheLy5csiIyND+Pv7izVr1hjreMK4IiIlJjV9BACrj927dxvrNDU1icWLF4uBAwcKf39/8eKLL4qKigrj/LS0NKttDB06VLGu3NxcER8fL7y9vcXw4cMV63AHzorVxo0bxYgRI4Svr68IDg4W06ZNEzk5OU7c0t6zR6xycnJEQkKCGDBggPD19RUxMTFi1apVFpeN5biyLVaeMK6EsE+8zHV1SWKOLUvWYuUJY8sesfriiy9EfHy8CAgIEP369RPjx48XO3bssLhfj7uPKyJSkoQwucYhERERERGRm+E5NURERERE5NaY1BARERERkVtjUkNERERERG6NSQ0REREREbk1JjVEREREROTWmNQQEREREZFbY1JDRERERERujUkNERERERG5NSY1REQmhBCYMWMGkpKSLOZlZGQgKCgI165dc0HPiIiIqCtMaoiITEiShN27d+P06dPYuXOnsbysrAwrV67E1q1bERkZadd1trW12bU9IiKiBw2TGiIiM1qtFlu2bMEf/vAHlJWVQQiB+fPnY+bMmZgwYQKeffZZBAQEICwsDL/+9a9RW1trXPbw4cN48sknERQUhEGDBuG5555DaWmpcX55eTkkScL+/fsxdepU+Pr6Yt++fa7YTCIiIo8hCSGEqztBRNQXzZ49G3V1dXjppZfw17/+FUVFRYiLi8Mbb7yBV155BU1NTVi1ahV0Oh1ycnIAAFlZWZAkCePGjcOdO3ewZs0alJeXIz8/HyqVCuXl5Rg2bBiio6Px7rvvYsKECfD19cWQIUNcvLVERETui0kNEVEXqqurERcXh5s3byIrKwvnz5/H8ePHceTIEWOda9euQavVoqSkBI888ohFG7W1tQgJCUFhYSHGjBljTGo2b96MZcuWOXNziIiIPBYPPyMi6kJoaCh+97vfITY2FrNnz0ZBQQFyc3MREBBgfIwaNQoAjIeYXb58GcnJyRg+fDgCAwMRHR0NALh69aqi7UmTJjl1W4iIiDyZxtUdICLqyzQaDTQaw1vlnTt3MGvWLGzcuNGiXsfhY7NmzcLQoUORmZmJiIgIyLKMMWPGoLW1VVG/X79+ju88ERHRA4JJDRGRjR599FFkZWUhOjramOiYunHjBkpKSpCZmYmf/OQnAIATJ044u5tEREQPHB5+RkRko5SUFNy8eRPJycn45ptvUFpaiiNHjuC1116DXq/HwIEDMWjQILz33nu4cuUKcnJykJqa6upuExEReTwmNURENoqIiMDJkyeh1+sxc+ZMjB07FsuXL0dQUBBUKhVUKhU++ugjnD17FmPGjMHvf/97pKenu7rbREREHo9XPyMiIiIiIrfGX2qIiIiIiMitMakhIiIiIiK3xqSGiIiIiIjcGpMaIiIiIiJya0xqiIiIiIjIrTGpISIiIiIit8akhoiIiIiI3BqTGiIiIiIicmtMaoiIiIiIyK0xqSEiIiIiIrfGpIaIiIiIiNwakxoiIiIiInJr/w+n3+AKS9i+KAAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "y2020solpv=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESOLPV')) & (d_vars['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025solpv=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESOLPV')) & (d_vars['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030solpv=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESOLPV')) & (d_vars['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035solpv=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESOLPV')) & (d_vars['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040solpv=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESOLPV')) & (d_vars['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045solpv=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESOLPV')) & (d_vars['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050solpv=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESOLPV')) & (d_vars['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020wind=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEWINON')) & (d_vars['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025wind=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEWINON')) & (d_vars['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030wind=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEWINON')) & (d_vars['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035wind=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEWINON')) & (d_vars['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040wind=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEWINON')) & (d_vars['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045wind=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEWINON')) & (d_vars['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050wind=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEWINON')) & (d_vars['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020solth=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESOLTH')) & (d_vars['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025solth=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESOLTH')) & (d_vars['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030solth=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESOLTH')) & (d_vars['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035solth=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESOLTH')) & (d_vars['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040solth=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESOLTH')) & (d_vars['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045solth=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESOLTH')) & (d_vars['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050solth=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESOLTH')) & (d_vars['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020solte=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESOLTE')) & (d_vars['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025solte=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESOLTE')) & (d_vars['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030solte=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESOLTE')) & (d_vars['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035solte=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESOLTE')) & (d_vars['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040solte=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESOLTE')) & (d_vars['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045solte=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESOLTE')) & (d_vars['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050solte=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESOLTE')) & (d_vars['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020biomec=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOMEC')) & (d_vars['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025biomec=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOMEC')) & (d_vars['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030biomec=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOMEC')) & (d_vars['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035biomec=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOMEC')) & (d_vars['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040biomec=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOMEC')) & (d_vars['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045biomec=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOMEC')) & (d_vars['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050biomec=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOMEC')) & (d_vars['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020biomaw=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOMAW')) & (d_vars['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025biomaw=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOMAW')) & (d_vars['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030biomaw=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOMAW')) & (d_vars['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035biomaw=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOMAW')) & (d_vars['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040biomaw=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOMAW')) & (d_vars['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045biomaw=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOMAW')) & (d_vars['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050biomaw=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOMAW')) & (d_vars['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020biomfw=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOMFW')) & (d_vars['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025biomfw=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOMFW')) & (d_vars['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030biomfw=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOMFW')) & (d_vars['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035biomfw=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOMFW')) & (d_vars['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040biomfw=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOMFW')) & (d_vars['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045biomfw=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOMFW')) & (d_vars['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050biomfw=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOMFW')) & (d_vars['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020swast=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESWAST')) & (d_vars['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025swast=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESWAST')) & (d_vars['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030swast=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESWAST')) & (d_vars['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035swast=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESWAST')) & (d_vars['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040swast=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESWAST')) & (d_vars['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045swast=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESWAST')) & (d_vars['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050swast=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPESWAST')) & (d_vars['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020bioethpi=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOETHPI')) & (d_vars['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025bioethpi=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOETHPI')) & (d_vars['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030bioethpi=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOETHPI')) & (d_vars['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035bioethpi=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOETHPI')) & (d_vars['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040bioethpi=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOETHPI')) & (d_vars['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045bioethpi=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOETHPI')) & (d_vars['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050bioethpi=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOETHPI')) & (d_vars['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020biodiepi=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIODIEPI')) & (d_vars['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025biodiepi=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIODIEPI')) & (d_vars['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030biodiepi=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIODIEPI')) & (d_vars['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035biodiepi=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIODIEPI')) & (d_vars['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040biodiepi=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIODIEPI')) & (d_vars['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045biodiepi=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIODIEPI')) & (d_vars['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050biodiepi=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIODIEPI')) & (d_vars['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020biogas=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOGAS')) & (d_vars['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025biogas=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOGAS')) & (d_vars['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030biogas=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOGAS')) & (d_vars['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035biogas=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOGAS')) & (d_vars['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040biogas=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOGAS')) & (d_vars['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045biogas=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOGAS')) & (d_vars['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050biogas=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEBIOGAS')) & (d_vars['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020hydro=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEHYDRR')) & (d_vars['vQPEDom'].sYear=='y2020')].vQPEDom.sum() + d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEHYDRC')) & (d_vars['vQPEDom'].sYear=='y2020')].vQPEDom.sum() + d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEMNHYDR')) & (d_vars['vQPEDom'].sYear=='y2020')].vQPEDom.sum()\n", + "y2025hydro=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEHYDRR')) & (d_vars['vQPEDom'].sYear=='y2025')].vQPEDom.sum() + d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEHYDRC')) & (d_vars['vQPEDom'].sYear=='y2025')].vQPEDom.sum() + d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEMNHYDR')) & (d_vars['vQPEDom'].sYear=='y2025')].vQPEDom.sum()\n", + "y2030hydro=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEHYDRR')) & (d_vars['vQPEDom'].sYear=='y2030')].vQPEDom.sum() + d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEHYDRC')) & (d_vars['vQPEDom'].sYear=='y2030')].vQPEDom.sum() + d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEMNHYDR')) & (d_vars['vQPEDom'].sYear=='y2030')].vQPEDom.sum()\n", + "y2035hydro=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEHYDRR')) & (d_vars['vQPEDom'].sYear=='y2035')].vQPEDom.sum() + d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEHYDRC')) & (d_vars['vQPEDom'].sYear=='y2035')].vQPEDom.sum() + d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEMNHYDR')) & (d_vars['vQPEDom'].sYear=='y2035')].vQPEDom.sum()\n", + "y2040hydro=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEHYDRR')) & (d_vars['vQPEDom'].sYear=='y2040')].vQPEDom.sum() + d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEHYDRC')) & (d_vars['vQPEDom'].sYear=='y2040')].vQPEDom.sum() + d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEMNHYDR')) & (d_vars['vQPEDom'].sYear=='y2040')].vQPEDom.sum()\n", + "y2045hydro=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEHYDRR')) & (d_vars['vQPEDom'].sYear=='y2045')].vQPEDom.sum() + d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEHYDRC')) & (d_vars['vQPEDom'].sYear=='y2045')].vQPEDom.sum() + d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEMNHYDR')) & (d_vars['vQPEDom'].sYear=='y2045')].vQPEDom.sum()\n", + "y2050hydro=d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEHYDRR')) & (d_vars['vQPEDom'].sYear=='y2050')].vQPEDom.sum() + d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEHYDRC')) & (d_vars['vQPEDom'].sYear=='y2050')].vQPEDom.sum() + d_vars['vQPEDom'][(d_vars['vQPEDom'].sPE.str.startswith('sPEMNHYDR')) & (d_vars['vQPEDom'].sYear=='y2050')].vQPEDom.sum()\n", + "\n", + "y2020nuclear=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPENUCLE')) & (d_vars['vQPEImp'].sYear=='y2020')].vQPEImp.sum()\n", + "y2025nuclear=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPENUCLE')) & (d_vars['vQPEImp'].sYear=='y2025')].vQPEImp.sum()\n", + "y2030nuclear=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPENUCLE')) & (d_vars['vQPEImp'].sYear=='y2030')].vQPEImp.sum()\n", + "y2035nuclear=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPENUCLE')) & (d_vars['vQPEImp'].sYear=='y2035')].vQPEImp.sum()\n", + "y2040nuclear=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPENUCLE')) & (d_vars['vQPEImp'].sYear=='y2040')].vQPEImp.sum()\n", + "y2045nuclear=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPENUCLE')) & (d_vars['vQPEImp'].sYear=='y2045')].vQPEImp.sum()\n", + "y2050nuclear=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPENUCLE')) & (d_vars['vQPEImp'].sYear=='y2050')].vQPEImp.sum()\n", + "\n", + "y2020impcoal=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPEIMPCO')) & (d_vars['vQPEImp'].sYear=='y2020')].vQPEImp.sum()\n", + "y2025impcoal=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPEIMPCO')) & (d_vars['vQPEImp'].sYear=='y2025')].vQPEImp.sum()\n", + "y2030impcoal=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPEIMPCO')) & (d_vars['vQPEImp'].sYear=='y2030')].vQPEImp.sum()\n", + "y2035impcoal=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPEIMPCO')) & (d_vars['vQPEImp'].sYear=='y2035')].vQPEImp.sum()\n", + "y2040impcoal=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPEIMPCO')) & (d_vars['vQPEImp'].sYear=='y2040')].vQPEImp.sum()\n", + "y2045impcoal=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPEIMPCO')) & (d_vars['vQPEImp'].sYear=='y2045')].vQPEImp.sum()\n", + "y2050impcoal=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPEIMPCO')) & (d_vars['vQPEImp'].sYear=='y2050')].vQPEImp.sum()\n", + "\n", + "y2020nagas=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPENAGAS')) & (d_vars['vQPEImp'].sYear=='y2020')].vQPEImp.sum()\n", + "y2025nagas=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPENAGAS')) & (d_vars['vQPEImp'].sYear=='y2025')].vQPEImp.sum()\n", + "y2030nagas=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPENAGAS')) & (d_vars['vQPEImp'].sYear=='y2030')].vQPEImp.sum()\n", + "y2035nagas=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPENAGAS')) & (d_vars['vQPEImp'].sYear=='y2035')].vQPEImp.sum()\n", + "y2040nagas=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPENAGAS')) & (d_vars['vQPEImp'].sYear=='y2040')].vQPEImp.sum()\n", + "y2045nagas=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPENAGAS')) & (d_vars['vQPEImp'].sYear=='y2045')].vQPEImp.sum()\n", + "y2050nagas=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPENAGAS')) & (d_vars['vQPEImp'].sYear=='y2050')].vQPEImp.sum()\n", + "\n", + "y2020lngas=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPELNGAS')) & (d_vars['vQPEImp'].sYear=='y2020')].vQPEImp.sum()\n", + "y2025lngas=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPELNGAS')) & (d_vars['vQPEImp'].sYear=='y2025')].vQPEImp.sum()\n", + "y2030lngas=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPELNGAS')) & (d_vars['vQPEImp'].sYear=='y2030')].vQPEImp.sum()\n", + "y2035lngas=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPELNGAS')) & (d_vars['vQPEImp'].sYear=='y2035')].vQPEImp.sum()\n", + "y2040lngas=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPELNGAS')) & (d_vars['vQPEImp'].sYear=='y2040')].vQPEImp.sum()\n", + "y2045lngas=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPELNGAS')) & (d_vars['vQPEImp'].sYear=='y2045')].vQPEImp.sum()\n", + "y2050lngas=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPELNGAS')) & (d_vars['vQPEImp'].sYear=='y2050')].vQPEImp.sum()\n", + "\n", + "y2020croil=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPECROIL')) & (d_vars['vQPEImp'].sYear=='y2020')].vQPEImp.sum()\n", + "y2025croil=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPECROIL')) & (d_vars['vQPEImp'].sYear=='y2025')].vQPEImp.sum()\n", + "y2030croil=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPECROIL')) & (d_vars['vQPEImp'].sYear=='y2030')].vQPEImp.sum()\n", + "y2035croil=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPECROIL')) & (d_vars['vQPEImp'].sYear=='y2035')].vQPEImp.sum()\n", + "y2040croil=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPECROIL')) & (d_vars['vQPEImp'].sYear=='y2040')].vQPEImp.sum()\n", + "y2045croil=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPECROIL')) & (d_vars['vQPEImp'].sYear=='y2045')].vQPEImp.sum()\n", + "y2050croil=d_vars['vQPEImp'][(d_vars['vQPEImp'].sPE.str.startswith('sPECROIL')) & (d_vars['vQPEImp'].sYear=='y2050')].vQPEImp.sum()\n", + "\n", + "\n", + "\n", + "\n", + "#Visualize the results in a bar plot for each year unstacking the results for Solar PV and Hydro\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "solpv = [y2020solpv, y2025solpv, y2030solpv, y2035solpv, y2040solpv, y2045solpv, y2050solpv]\n", + "hydro = [y2020hydro, y2025hydro, y2030hydro, y2035hydro, y2040hydro, y2045hydro, y2050hydro]\n", + "wind = [y2020wind, y2025wind, y2030wind, y2035wind, y2040wind, y2045wind, y2050wind]\n", + "solte = [y2020solte, y2025solte, y2030solte, y2035solte, y2040solte, y2045solte, y2050solte]\n", + "solth = [y2020solth, y2025solth, y2030solth, y2035solth, y2040solth, y2045solth, y2050solth]\n", + "biomec = [y2020biomec, y2025biomec, y2030biomec, y2035biomec, y2040biomec, y2045biomec, y2050biomec]\n", + "biomaw = [y2020biomaw, y2025biomaw, y2030biomaw, y2035biomaw, y2040biomaw, y2045biomaw, y2050biomaw]\n", + "biomfw = [y2020biomfw, y2025biomfw, y2030biomfw, y2035biomfw, y2040biomfw, y2045biomfw, y2050biomfw]\n", + "swast = [y2020swast, y2025swast, y2030swast, y2035swast, y2040swast, y2045swast, y2050swast]\n", + "bioethpi = [y2020bioethpi, y2025bioethpi, y2030bioethpi, y2035bioethpi, y2040bioethpi, y2045bioethpi, y2050bioethpi]\n", + "biodiepi = [y2020biodiepi, y2025biodiepi, y2030biodiepi, y2035biodiepi, y2040biodiepi, y2045biodiepi, y2050biodiepi]\n", + "biogas = [y2020biogas, y2025biogas, y2030biogas, y2035biogas, y2040biogas, y2045biogas, y2050biogas]\n", + "nuclear = [y2020nuclear, y2025nuclear, y2030nuclear, y2035nuclear, y2040nuclear, y2045nuclear, y2050nuclear]\n", + "impcoal = [y2020impcoal, y2025impcoal, y2030impcoal, y2035impcoal, y2040impcoal, y2045impcoal, y2050impcoal]\n", + "nagas = [y2020nagas, y2025nagas, y2030nagas, y2035nagas, y2040nagas, y2045nagas, y2050nagas]\n", + "lngas = [y2020lngas, y2025lngas, y2030lngas, y2035lngas, y2040lngas, y2045lngas, y2050lngas]\n", + "croil = [y2020croil, y2025croil, y2030croil, y2035croil, y2040croil, y2045croil, y2050croil]\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "plt.plot(years, solpv, label='Solar PV',color='yellow')\n", + "plt.plot(years, hydro, label='Hydro',color='blue')\n", + "plt.plot(years, wind, label='Wind',color='green')\n", + "plt.plot(years,solte, label='Solar Termoeléctrica',color='orange')\n", + "plt.plot(years,solth, label='Solar Térmica',color='red')\n", + "plt.plot(years,biomec, label='BiomasaEC',color='purple')\n", + "plt.plot(years,biomaw, label='BiomassAW',color='pink')\n", + "plt.plot(years,biomfw, label='BiomassFW')\n", + "plt.plot(years,swast, label='Residuos Sólidos')\n", + "plt.plot(years,bioethpi, label='BioetanolPI')\n", + "plt.plot(years,biodiepi, label='BiodieselPI')\n", + "plt.plot(years,biogas, label='Biogás')\n", + "plt.plot(years,nuclear, label='Nuclear')\n", + "plt.plot(years,impcoal, label='Carbón Importado',color='black')\n", + "plt.plot(years,nagas, label='NG')\n", + "plt.plot(years,lngas, label='LNG')\n", + "plt.plot(years,croil, label='Crudo')\n", + "plt.xlabel('Year')\n", + "plt.ylabel('[GWh]')\n", + "plt.title('Primary energy')\n", + "# Add a legend outside of the plot\n", + "# Change the color of the plots to gradient of blue\n", + "\n", + "plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.0" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sYear=='y2050') & (d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOIGCC'))].vQCEPriOUT.sum()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2020_PEImp = y2020_PEImp[~y2020_PEImp.sPE.str.startswith('sPEHYDRR')][~y2020_PEImp.sPE.str.startswith('sPEHYDRC')][~y2020_PEImp.sPE.str.startswith('sPEMNHY')][~y2020_PEImp.sPE.str.startswith('sPEWINON')][~y2020_PEImp.sPE.str.startswith('sPEWINOF')][~y2020_PEImp.sPE.str.startswith('sPESOLPV')][~y2020_PEImp.sPE.str.startswith('sPESOLTE')][~y2020_PEImp.sPE.str.startswith('sPESOLTH')][~y2020_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2020_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2020_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2020_PEImp.sPE.str.startswith('sPESWAST')][~y2020_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2020_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2020_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2020_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2020_PEImp = y2020_PEImp[~y2020_PEImp.sPE.str.startswith('sPEHYDRR')][~y2020_PEImp.sPE.str.startswith('sPEHYDRC')][~y2020_PEImp.sPE.str.startswith('sPEMNHY')][~y2020_PEImp.sPE.str.startswith('sPEWINON')][~y2020_PEImp.sPE.str.startswith('sPEWINOF')][~y2020_PEImp.sPE.str.startswith('sPESOLPV')][~y2020_PEImp.sPE.str.startswith('sPESOLTE')][~y2020_PEImp.sPE.str.startswith('sPESOLTH')][~y2020_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2020_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2020_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2020_PEImp.sPE.str.startswith('sPESWAST')][~y2020_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2020_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2020_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2020_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2020_PEImp = y2020_PEImp[~y2020_PEImp.sPE.str.startswith('sPEHYDRR')][~y2020_PEImp.sPE.str.startswith('sPEHYDRC')][~y2020_PEImp.sPE.str.startswith('sPEMNHY')][~y2020_PEImp.sPE.str.startswith('sPEWINON')][~y2020_PEImp.sPE.str.startswith('sPEWINOF')][~y2020_PEImp.sPE.str.startswith('sPESOLPV')][~y2020_PEImp.sPE.str.startswith('sPESOLTE')][~y2020_PEImp.sPE.str.startswith('sPESOLTH')][~y2020_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2020_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2020_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2020_PEImp.sPE.str.startswith('sPESWAST')][~y2020_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2020_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2020_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2020_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2020_PEImp = y2020_PEImp[~y2020_PEImp.sPE.str.startswith('sPEHYDRR')][~y2020_PEImp.sPE.str.startswith('sPEHYDRC')][~y2020_PEImp.sPE.str.startswith('sPEMNHY')][~y2020_PEImp.sPE.str.startswith('sPEWINON')][~y2020_PEImp.sPE.str.startswith('sPEWINOF')][~y2020_PEImp.sPE.str.startswith('sPESOLPV')][~y2020_PEImp.sPE.str.startswith('sPESOLTE')][~y2020_PEImp.sPE.str.startswith('sPESOLTH')][~y2020_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2020_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2020_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2020_PEImp.sPE.str.startswith('sPESWAST')][~y2020_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2020_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2020_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2020_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2020_PEImp = y2020_PEImp[~y2020_PEImp.sPE.str.startswith('sPEHYDRR')][~y2020_PEImp.sPE.str.startswith('sPEHYDRC')][~y2020_PEImp.sPE.str.startswith('sPEMNHY')][~y2020_PEImp.sPE.str.startswith('sPEWINON')][~y2020_PEImp.sPE.str.startswith('sPEWINOF')][~y2020_PEImp.sPE.str.startswith('sPESOLPV')][~y2020_PEImp.sPE.str.startswith('sPESOLTE')][~y2020_PEImp.sPE.str.startswith('sPESOLTH')][~y2020_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2020_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2020_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2020_PEImp.sPE.str.startswith('sPESWAST')][~y2020_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2020_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2020_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2020_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2020_PEImp = y2020_PEImp[~y2020_PEImp.sPE.str.startswith('sPEHYDRR')][~y2020_PEImp.sPE.str.startswith('sPEHYDRC')][~y2020_PEImp.sPE.str.startswith('sPEMNHY')][~y2020_PEImp.sPE.str.startswith('sPEWINON')][~y2020_PEImp.sPE.str.startswith('sPEWINOF')][~y2020_PEImp.sPE.str.startswith('sPESOLPV')][~y2020_PEImp.sPE.str.startswith('sPESOLTE')][~y2020_PEImp.sPE.str.startswith('sPESOLTH')][~y2020_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2020_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2020_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2020_PEImp.sPE.str.startswith('sPESWAST')][~y2020_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2020_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2020_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2020_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2020_PEImp = y2020_PEImp[~y2020_PEImp.sPE.str.startswith('sPEHYDRR')][~y2020_PEImp.sPE.str.startswith('sPEHYDRC')][~y2020_PEImp.sPE.str.startswith('sPEMNHY')][~y2020_PEImp.sPE.str.startswith('sPEWINON')][~y2020_PEImp.sPE.str.startswith('sPEWINOF')][~y2020_PEImp.sPE.str.startswith('sPESOLPV')][~y2020_PEImp.sPE.str.startswith('sPESOLTE')][~y2020_PEImp.sPE.str.startswith('sPESOLTH')][~y2020_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2020_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2020_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2020_PEImp.sPE.str.startswith('sPESWAST')][~y2020_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2020_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2020_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2020_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2020_PEImp = y2020_PEImp[~y2020_PEImp.sPE.str.startswith('sPEHYDRR')][~y2020_PEImp.sPE.str.startswith('sPEHYDRC')][~y2020_PEImp.sPE.str.startswith('sPEMNHY')][~y2020_PEImp.sPE.str.startswith('sPEWINON')][~y2020_PEImp.sPE.str.startswith('sPEWINOF')][~y2020_PEImp.sPE.str.startswith('sPESOLPV')][~y2020_PEImp.sPE.str.startswith('sPESOLTE')][~y2020_PEImp.sPE.str.startswith('sPESOLTH')][~y2020_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2020_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2020_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2020_PEImp.sPE.str.startswith('sPESWAST')][~y2020_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2020_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2020_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2020_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2020_PEImp = y2020_PEImp[~y2020_PEImp.sPE.str.startswith('sPEHYDRR')][~y2020_PEImp.sPE.str.startswith('sPEHYDRC')][~y2020_PEImp.sPE.str.startswith('sPEMNHY')][~y2020_PEImp.sPE.str.startswith('sPEWINON')][~y2020_PEImp.sPE.str.startswith('sPEWINOF')][~y2020_PEImp.sPE.str.startswith('sPESOLPV')][~y2020_PEImp.sPE.str.startswith('sPESOLTE')][~y2020_PEImp.sPE.str.startswith('sPESOLTH')][~y2020_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2020_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2020_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2020_PEImp.sPE.str.startswith('sPESWAST')][~y2020_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2020_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2020_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2020_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2020_PEImp = y2020_PEImp[~y2020_PEImp.sPE.str.startswith('sPEHYDRR')][~y2020_PEImp.sPE.str.startswith('sPEHYDRC')][~y2020_PEImp.sPE.str.startswith('sPEMNHY')][~y2020_PEImp.sPE.str.startswith('sPEWINON')][~y2020_PEImp.sPE.str.startswith('sPEWINOF')][~y2020_PEImp.sPE.str.startswith('sPESOLPV')][~y2020_PEImp.sPE.str.startswith('sPESOLTE')][~y2020_PEImp.sPE.str.startswith('sPESOLTH')][~y2020_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2020_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2020_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2020_PEImp.sPE.str.startswith('sPESWAST')][~y2020_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2020_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2020_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2020_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2020_PEImp = y2020_PEImp[~y2020_PEImp.sPE.str.startswith('sPEHYDRR')][~y2020_PEImp.sPE.str.startswith('sPEHYDRC')][~y2020_PEImp.sPE.str.startswith('sPEMNHY')][~y2020_PEImp.sPE.str.startswith('sPEWINON')][~y2020_PEImp.sPE.str.startswith('sPEWINOF')][~y2020_PEImp.sPE.str.startswith('sPESOLPV')][~y2020_PEImp.sPE.str.startswith('sPESOLTE')][~y2020_PEImp.sPE.str.startswith('sPESOLTH')][~y2020_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2020_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2020_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2020_PEImp.sPE.str.startswith('sPESWAST')][~y2020_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2020_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2020_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2020_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2020_PEImp = y2020_PEImp[~y2020_PEImp.sPE.str.startswith('sPEHYDRR')][~y2020_PEImp.sPE.str.startswith('sPEHYDRC')][~y2020_PEImp.sPE.str.startswith('sPEMNHY')][~y2020_PEImp.sPE.str.startswith('sPEWINON')][~y2020_PEImp.sPE.str.startswith('sPEWINOF')][~y2020_PEImp.sPE.str.startswith('sPESOLPV')][~y2020_PEImp.sPE.str.startswith('sPESOLTE')][~y2020_PEImp.sPE.str.startswith('sPESOLTH')][~y2020_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2020_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2020_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2020_PEImp.sPE.str.startswith('sPESWAST')][~y2020_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2020_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2020_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2020_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2020_PEImp = y2020_PEImp[~y2020_PEImp.sPE.str.startswith('sPEHYDRR')][~y2020_PEImp.sPE.str.startswith('sPEHYDRC')][~y2020_PEImp.sPE.str.startswith('sPEMNHY')][~y2020_PEImp.sPE.str.startswith('sPEWINON')][~y2020_PEImp.sPE.str.startswith('sPEWINOF')][~y2020_PEImp.sPE.str.startswith('sPESOLPV')][~y2020_PEImp.sPE.str.startswith('sPESOLTE')][~y2020_PEImp.sPE.str.startswith('sPESOLTH')][~y2020_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2020_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2020_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2020_PEImp.sPE.str.startswith('sPESWAST')][~y2020_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2020_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2020_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2020_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2020_PEImp = y2020_PEImp[~y2020_PEImp.sPE.str.startswith('sPEHYDRR')][~y2020_PEImp.sPE.str.startswith('sPEHYDRC')][~y2020_PEImp.sPE.str.startswith('sPEMNHY')][~y2020_PEImp.sPE.str.startswith('sPEWINON')][~y2020_PEImp.sPE.str.startswith('sPEWINOF')][~y2020_PEImp.sPE.str.startswith('sPESOLPV')][~y2020_PEImp.sPE.str.startswith('sPESOLTE')][~y2020_PEImp.sPE.str.startswith('sPESOLTH')][~y2020_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2020_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2020_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2020_PEImp.sPE.str.startswith('sPESWAST')][~y2020_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2020_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2020_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2020_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:10: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2020_PEImp = y2020_PEImp[~y2020_PEImp.sPE.str.startswith('sPEHYDRR')][~y2020_PEImp.sPE.str.startswith('sPEHYDRC')][~y2020_PEImp.sPE.str.startswith('sPEMNHY')][~y2020_PEImp.sPE.str.startswith('sPEWINON')][~y2020_PEImp.sPE.str.startswith('sPEWINOF')][~y2020_PEImp.sPE.str.startswith('sPESOLPV')][~y2020_PEImp.sPE.str.startswith('sPESOLTE')][~y2020_PEImp.sPE.str.startswith('sPESOLTH')][~y2020_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2020_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2020_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2020_PEImp.sPE.str.startswith('sPESWAST')][~y2020_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2020_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2020_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2020_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:11: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2025_PEImp = y2025_PEImp[~y2025_PEImp.sPE.str.startswith('sPEHYDRR')][~y2025_PEImp.sPE.str.startswith('sPEHYDRC')][~y2025_PEImp.sPE.str.startswith('sPEMNHY')][~y2025_PEImp.sPE.str.startswith('sPEWINON')][~y2025_PEImp.sPE.str.startswith('sPEWINOF')][~y2025_PEImp.sPE.str.startswith('sPESOLPV')][~y2025_PEImp.sPE.str.startswith('sPESOLTE')][~y2025_PEImp.sPE.str.startswith('sPESOLTH')][~y2025_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2025_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2025_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2025_PEImp.sPE.str.startswith('sPESWAST')][~y2025_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2025_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2025_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2025_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:11: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2025_PEImp = y2025_PEImp[~y2025_PEImp.sPE.str.startswith('sPEHYDRR')][~y2025_PEImp.sPE.str.startswith('sPEHYDRC')][~y2025_PEImp.sPE.str.startswith('sPEMNHY')][~y2025_PEImp.sPE.str.startswith('sPEWINON')][~y2025_PEImp.sPE.str.startswith('sPEWINOF')][~y2025_PEImp.sPE.str.startswith('sPESOLPV')][~y2025_PEImp.sPE.str.startswith('sPESOLTE')][~y2025_PEImp.sPE.str.startswith('sPESOLTH')][~y2025_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2025_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2025_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2025_PEImp.sPE.str.startswith('sPESWAST')][~y2025_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2025_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2025_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2025_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:11: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2025_PEImp = y2025_PEImp[~y2025_PEImp.sPE.str.startswith('sPEHYDRR')][~y2025_PEImp.sPE.str.startswith('sPEHYDRC')][~y2025_PEImp.sPE.str.startswith('sPEMNHY')][~y2025_PEImp.sPE.str.startswith('sPEWINON')][~y2025_PEImp.sPE.str.startswith('sPEWINOF')][~y2025_PEImp.sPE.str.startswith('sPESOLPV')][~y2025_PEImp.sPE.str.startswith('sPESOLTE')][~y2025_PEImp.sPE.str.startswith('sPESOLTH')][~y2025_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2025_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2025_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2025_PEImp.sPE.str.startswith('sPESWAST')][~y2025_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2025_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2025_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2025_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:11: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2025_PEImp = y2025_PEImp[~y2025_PEImp.sPE.str.startswith('sPEHYDRR')][~y2025_PEImp.sPE.str.startswith('sPEHYDRC')][~y2025_PEImp.sPE.str.startswith('sPEMNHY')][~y2025_PEImp.sPE.str.startswith('sPEWINON')][~y2025_PEImp.sPE.str.startswith('sPEWINOF')][~y2025_PEImp.sPE.str.startswith('sPESOLPV')][~y2025_PEImp.sPE.str.startswith('sPESOLTE')][~y2025_PEImp.sPE.str.startswith('sPESOLTH')][~y2025_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2025_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2025_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2025_PEImp.sPE.str.startswith('sPESWAST')][~y2025_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2025_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2025_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2025_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:11: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2025_PEImp = y2025_PEImp[~y2025_PEImp.sPE.str.startswith('sPEHYDRR')][~y2025_PEImp.sPE.str.startswith('sPEHYDRC')][~y2025_PEImp.sPE.str.startswith('sPEMNHY')][~y2025_PEImp.sPE.str.startswith('sPEWINON')][~y2025_PEImp.sPE.str.startswith('sPEWINOF')][~y2025_PEImp.sPE.str.startswith('sPESOLPV')][~y2025_PEImp.sPE.str.startswith('sPESOLTE')][~y2025_PEImp.sPE.str.startswith('sPESOLTH')][~y2025_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2025_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2025_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2025_PEImp.sPE.str.startswith('sPESWAST')][~y2025_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2025_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2025_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2025_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:11: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2025_PEImp = y2025_PEImp[~y2025_PEImp.sPE.str.startswith('sPEHYDRR')][~y2025_PEImp.sPE.str.startswith('sPEHYDRC')][~y2025_PEImp.sPE.str.startswith('sPEMNHY')][~y2025_PEImp.sPE.str.startswith('sPEWINON')][~y2025_PEImp.sPE.str.startswith('sPEWINOF')][~y2025_PEImp.sPE.str.startswith('sPESOLPV')][~y2025_PEImp.sPE.str.startswith('sPESOLTE')][~y2025_PEImp.sPE.str.startswith('sPESOLTH')][~y2025_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2025_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2025_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2025_PEImp.sPE.str.startswith('sPESWAST')][~y2025_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2025_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2025_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2025_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:11: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2025_PEImp = y2025_PEImp[~y2025_PEImp.sPE.str.startswith('sPEHYDRR')][~y2025_PEImp.sPE.str.startswith('sPEHYDRC')][~y2025_PEImp.sPE.str.startswith('sPEMNHY')][~y2025_PEImp.sPE.str.startswith('sPEWINON')][~y2025_PEImp.sPE.str.startswith('sPEWINOF')][~y2025_PEImp.sPE.str.startswith('sPESOLPV')][~y2025_PEImp.sPE.str.startswith('sPESOLTE')][~y2025_PEImp.sPE.str.startswith('sPESOLTH')][~y2025_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2025_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2025_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2025_PEImp.sPE.str.startswith('sPESWAST')][~y2025_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2025_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2025_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2025_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:11: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2025_PEImp = y2025_PEImp[~y2025_PEImp.sPE.str.startswith('sPEHYDRR')][~y2025_PEImp.sPE.str.startswith('sPEHYDRC')][~y2025_PEImp.sPE.str.startswith('sPEMNHY')][~y2025_PEImp.sPE.str.startswith('sPEWINON')][~y2025_PEImp.sPE.str.startswith('sPEWINOF')][~y2025_PEImp.sPE.str.startswith('sPESOLPV')][~y2025_PEImp.sPE.str.startswith('sPESOLTE')][~y2025_PEImp.sPE.str.startswith('sPESOLTH')][~y2025_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2025_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2025_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2025_PEImp.sPE.str.startswith('sPESWAST')][~y2025_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2025_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2025_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2025_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:11: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2025_PEImp = y2025_PEImp[~y2025_PEImp.sPE.str.startswith('sPEHYDRR')][~y2025_PEImp.sPE.str.startswith('sPEHYDRC')][~y2025_PEImp.sPE.str.startswith('sPEMNHY')][~y2025_PEImp.sPE.str.startswith('sPEWINON')][~y2025_PEImp.sPE.str.startswith('sPEWINOF')][~y2025_PEImp.sPE.str.startswith('sPESOLPV')][~y2025_PEImp.sPE.str.startswith('sPESOLTE')][~y2025_PEImp.sPE.str.startswith('sPESOLTH')][~y2025_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2025_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2025_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2025_PEImp.sPE.str.startswith('sPESWAST')][~y2025_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2025_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2025_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2025_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:11: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2025_PEImp = y2025_PEImp[~y2025_PEImp.sPE.str.startswith('sPEHYDRR')][~y2025_PEImp.sPE.str.startswith('sPEHYDRC')][~y2025_PEImp.sPE.str.startswith('sPEMNHY')][~y2025_PEImp.sPE.str.startswith('sPEWINON')][~y2025_PEImp.sPE.str.startswith('sPEWINOF')][~y2025_PEImp.sPE.str.startswith('sPESOLPV')][~y2025_PEImp.sPE.str.startswith('sPESOLTE')][~y2025_PEImp.sPE.str.startswith('sPESOLTH')][~y2025_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2025_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2025_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2025_PEImp.sPE.str.startswith('sPESWAST')][~y2025_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2025_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2025_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2025_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:11: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2025_PEImp = y2025_PEImp[~y2025_PEImp.sPE.str.startswith('sPEHYDRR')][~y2025_PEImp.sPE.str.startswith('sPEHYDRC')][~y2025_PEImp.sPE.str.startswith('sPEMNHY')][~y2025_PEImp.sPE.str.startswith('sPEWINON')][~y2025_PEImp.sPE.str.startswith('sPEWINOF')][~y2025_PEImp.sPE.str.startswith('sPESOLPV')][~y2025_PEImp.sPE.str.startswith('sPESOLTE')][~y2025_PEImp.sPE.str.startswith('sPESOLTH')][~y2025_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2025_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2025_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2025_PEImp.sPE.str.startswith('sPESWAST')][~y2025_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2025_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2025_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2025_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:11: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2025_PEImp = y2025_PEImp[~y2025_PEImp.sPE.str.startswith('sPEHYDRR')][~y2025_PEImp.sPE.str.startswith('sPEHYDRC')][~y2025_PEImp.sPE.str.startswith('sPEMNHY')][~y2025_PEImp.sPE.str.startswith('sPEWINON')][~y2025_PEImp.sPE.str.startswith('sPEWINOF')][~y2025_PEImp.sPE.str.startswith('sPESOLPV')][~y2025_PEImp.sPE.str.startswith('sPESOLTE')][~y2025_PEImp.sPE.str.startswith('sPESOLTH')][~y2025_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2025_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2025_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2025_PEImp.sPE.str.startswith('sPESWAST')][~y2025_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2025_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2025_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2025_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:11: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2025_PEImp = y2025_PEImp[~y2025_PEImp.sPE.str.startswith('sPEHYDRR')][~y2025_PEImp.sPE.str.startswith('sPEHYDRC')][~y2025_PEImp.sPE.str.startswith('sPEMNHY')][~y2025_PEImp.sPE.str.startswith('sPEWINON')][~y2025_PEImp.sPE.str.startswith('sPEWINOF')][~y2025_PEImp.sPE.str.startswith('sPESOLPV')][~y2025_PEImp.sPE.str.startswith('sPESOLTE')][~y2025_PEImp.sPE.str.startswith('sPESOLTH')][~y2025_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2025_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2025_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2025_PEImp.sPE.str.startswith('sPESWAST')][~y2025_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2025_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2025_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2025_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:11: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2025_PEImp = y2025_PEImp[~y2025_PEImp.sPE.str.startswith('sPEHYDRR')][~y2025_PEImp.sPE.str.startswith('sPEHYDRC')][~y2025_PEImp.sPE.str.startswith('sPEMNHY')][~y2025_PEImp.sPE.str.startswith('sPEWINON')][~y2025_PEImp.sPE.str.startswith('sPEWINOF')][~y2025_PEImp.sPE.str.startswith('sPESOLPV')][~y2025_PEImp.sPE.str.startswith('sPESOLTE')][~y2025_PEImp.sPE.str.startswith('sPESOLTH')][~y2025_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2025_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2025_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2025_PEImp.sPE.str.startswith('sPESWAST')][~y2025_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2025_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2025_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2025_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:11: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2025_PEImp = y2025_PEImp[~y2025_PEImp.sPE.str.startswith('sPEHYDRR')][~y2025_PEImp.sPE.str.startswith('sPEHYDRC')][~y2025_PEImp.sPE.str.startswith('sPEMNHY')][~y2025_PEImp.sPE.str.startswith('sPEWINON')][~y2025_PEImp.sPE.str.startswith('sPEWINOF')][~y2025_PEImp.sPE.str.startswith('sPESOLPV')][~y2025_PEImp.sPE.str.startswith('sPESOLTE')][~y2025_PEImp.sPE.str.startswith('sPESOLTH')][~y2025_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2025_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2025_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2025_PEImp.sPE.str.startswith('sPESWAST')][~y2025_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2025_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2025_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2025_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:12: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2030_PEImp = y2030_PEImp[~y2030_PEImp.sPE.str.startswith('sPEHYDRR')][~y2030_PEImp.sPE.str.startswith('sPEHYDRC')][~y2030_PEImp.sPE.str.startswith('sPEMNHY')][~y2030_PEImp.sPE.str.startswith('sPEWINON')][~y2030_PEImp.sPE.str.startswith('sPEWINOF')][~y2030_PEImp.sPE.str.startswith('sPESOLPV')][~y2030_PEImp.sPE.str.startswith('sPESOLTE')][~y2030_PEImp.sPE.str.startswith('sPESOLTH')][~y2030_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2030_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2030_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2030_PEImp.sPE.str.startswith('sPESWAST')][~y2030_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2030_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2030_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2030_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:12: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2030_PEImp = y2030_PEImp[~y2030_PEImp.sPE.str.startswith('sPEHYDRR')][~y2030_PEImp.sPE.str.startswith('sPEHYDRC')][~y2030_PEImp.sPE.str.startswith('sPEMNHY')][~y2030_PEImp.sPE.str.startswith('sPEWINON')][~y2030_PEImp.sPE.str.startswith('sPEWINOF')][~y2030_PEImp.sPE.str.startswith('sPESOLPV')][~y2030_PEImp.sPE.str.startswith('sPESOLTE')][~y2030_PEImp.sPE.str.startswith('sPESOLTH')][~y2030_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2030_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2030_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2030_PEImp.sPE.str.startswith('sPESWAST')][~y2030_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2030_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2030_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2030_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:12: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2030_PEImp = y2030_PEImp[~y2030_PEImp.sPE.str.startswith('sPEHYDRR')][~y2030_PEImp.sPE.str.startswith('sPEHYDRC')][~y2030_PEImp.sPE.str.startswith('sPEMNHY')][~y2030_PEImp.sPE.str.startswith('sPEWINON')][~y2030_PEImp.sPE.str.startswith('sPEWINOF')][~y2030_PEImp.sPE.str.startswith('sPESOLPV')][~y2030_PEImp.sPE.str.startswith('sPESOLTE')][~y2030_PEImp.sPE.str.startswith('sPESOLTH')][~y2030_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2030_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2030_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2030_PEImp.sPE.str.startswith('sPESWAST')][~y2030_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2030_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2030_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2030_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:12: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2030_PEImp = y2030_PEImp[~y2030_PEImp.sPE.str.startswith('sPEHYDRR')][~y2030_PEImp.sPE.str.startswith('sPEHYDRC')][~y2030_PEImp.sPE.str.startswith('sPEMNHY')][~y2030_PEImp.sPE.str.startswith('sPEWINON')][~y2030_PEImp.sPE.str.startswith('sPEWINOF')][~y2030_PEImp.sPE.str.startswith('sPESOLPV')][~y2030_PEImp.sPE.str.startswith('sPESOLTE')][~y2030_PEImp.sPE.str.startswith('sPESOLTH')][~y2030_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2030_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2030_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2030_PEImp.sPE.str.startswith('sPESWAST')][~y2030_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2030_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2030_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2030_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:12: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2030_PEImp = y2030_PEImp[~y2030_PEImp.sPE.str.startswith('sPEHYDRR')][~y2030_PEImp.sPE.str.startswith('sPEHYDRC')][~y2030_PEImp.sPE.str.startswith('sPEMNHY')][~y2030_PEImp.sPE.str.startswith('sPEWINON')][~y2030_PEImp.sPE.str.startswith('sPEWINOF')][~y2030_PEImp.sPE.str.startswith('sPESOLPV')][~y2030_PEImp.sPE.str.startswith('sPESOLTE')][~y2030_PEImp.sPE.str.startswith('sPESOLTH')][~y2030_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2030_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2030_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2030_PEImp.sPE.str.startswith('sPESWAST')][~y2030_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2030_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2030_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2030_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:12: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2030_PEImp = y2030_PEImp[~y2030_PEImp.sPE.str.startswith('sPEHYDRR')][~y2030_PEImp.sPE.str.startswith('sPEHYDRC')][~y2030_PEImp.sPE.str.startswith('sPEMNHY')][~y2030_PEImp.sPE.str.startswith('sPEWINON')][~y2030_PEImp.sPE.str.startswith('sPEWINOF')][~y2030_PEImp.sPE.str.startswith('sPESOLPV')][~y2030_PEImp.sPE.str.startswith('sPESOLTE')][~y2030_PEImp.sPE.str.startswith('sPESOLTH')][~y2030_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2030_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2030_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2030_PEImp.sPE.str.startswith('sPESWAST')][~y2030_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2030_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2030_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2030_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:12: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2030_PEImp = y2030_PEImp[~y2030_PEImp.sPE.str.startswith('sPEHYDRR')][~y2030_PEImp.sPE.str.startswith('sPEHYDRC')][~y2030_PEImp.sPE.str.startswith('sPEMNHY')][~y2030_PEImp.sPE.str.startswith('sPEWINON')][~y2030_PEImp.sPE.str.startswith('sPEWINOF')][~y2030_PEImp.sPE.str.startswith('sPESOLPV')][~y2030_PEImp.sPE.str.startswith('sPESOLTE')][~y2030_PEImp.sPE.str.startswith('sPESOLTH')][~y2030_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2030_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2030_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2030_PEImp.sPE.str.startswith('sPESWAST')][~y2030_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2030_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2030_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2030_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:12: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2030_PEImp = y2030_PEImp[~y2030_PEImp.sPE.str.startswith('sPEHYDRR')][~y2030_PEImp.sPE.str.startswith('sPEHYDRC')][~y2030_PEImp.sPE.str.startswith('sPEMNHY')][~y2030_PEImp.sPE.str.startswith('sPEWINON')][~y2030_PEImp.sPE.str.startswith('sPEWINOF')][~y2030_PEImp.sPE.str.startswith('sPESOLPV')][~y2030_PEImp.sPE.str.startswith('sPESOLTE')][~y2030_PEImp.sPE.str.startswith('sPESOLTH')][~y2030_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2030_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2030_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2030_PEImp.sPE.str.startswith('sPESWAST')][~y2030_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2030_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2030_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2030_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:12: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2030_PEImp = y2030_PEImp[~y2030_PEImp.sPE.str.startswith('sPEHYDRR')][~y2030_PEImp.sPE.str.startswith('sPEHYDRC')][~y2030_PEImp.sPE.str.startswith('sPEMNHY')][~y2030_PEImp.sPE.str.startswith('sPEWINON')][~y2030_PEImp.sPE.str.startswith('sPEWINOF')][~y2030_PEImp.sPE.str.startswith('sPESOLPV')][~y2030_PEImp.sPE.str.startswith('sPESOLTE')][~y2030_PEImp.sPE.str.startswith('sPESOLTH')][~y2030_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2030_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2030_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2030_PEImp.sPE.str.startswith('sPESWAST')][~y2030_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2030_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2030_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2030_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:12: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2030_PEImp = y2030_PEImp[~y2030_PEImp.sPE.str.startswith('sPEHYDRR')][~y2030_PEImp.sPE.str.startswith('sPEHYDRC')][~y2030_PEImp.sPE.str.startswith('sPEMNHY')][~y2030_PEImp.sPE.str.startswith('sPEWINON')][~y2030_PEImp.sPE.str.startswith('sPEWINOF')][~y2030_PEImp.sPE.str.startswith('sPESOLPV')][~y2030_PEImp.sPE.str.startswith('sPESOLTE')][~y2030_PEImp.sPE.str.startswith('sPESOLTH')][~y2030_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2030_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2030_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2030_PEImp.sPE.str.startswith('sPESWAST')][~y2030_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2030_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2030_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2030_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:12: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2030_PEImp = y2030_PEImp[~y2030_PEImp.sPE.str.startswith('sPEHYDRR')][~y2030_PEImp.sPE.str.startswith('sPEHYDRC')][~y2030_PEImp.sPE.str.startswith('sPEMNHY')][~y2030_PEImp.sPE.str.startswith('sPEWINON')][~y2030_PEImp.sPE.str.startswith('sPEWINOF')][~y2030_PEImp.sPE.str.startswith('sPESOLPV')][~y2030_PEImp.sPE.str.startswith('sPESOLTE')][~y2030_PEImp.sPE.str.startswith('sPESOLTH')][~y2030_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2030_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2030_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2030_PEImp.sPE.str.startswith('sPESWAST')][~y2030_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2030_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2030_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2030_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:12: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2030_PEImp = y2030_PEImp[~y2030_PEImp.sPE.str.startswith('sPEHYDRR')][~y2030_PEImp.sPE.str.startswith('sPEHYDRC')][~y2030_PEImp.sPE.str.startswith('sPEMNHY')][~y2030_PEImp.sPE.str.startswith('sPEWINON')][~y2030_PEImp.sPE.str.startswith('sPEWINOF')][~y2030_PEImp.sPE.str.startswith('sPESOLPV')][~y2030_PEImp.sPE.str.startswith('sPESOLTE')][~y2030_PEImp.sPE.str.startswith('sPESOLTH')][~y2030_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2030_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2030_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2030_PEImp.sPE.str.startswith('sPESWAST')][~y2030_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2030_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2030_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2030_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:12: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2030_PEImp = y2030_PEImp[~y2030_PEImp.sPE.str.startswith('sPEHYDRR')][~y2030_PEImp.sPE.str.startswith('sPEHYDRC')][~y2030_PEImp.sPE.str.startswith('sPEMNHY')][~y2030_PEImp.sPE.str.startswith('sPEWINON')][~y2030_PEImp.sPE.str.startswith('sPEWINOF')][~y2030_PEImp.sPE.str.startswith('sPESOLPV')][~y2030_PEImp.sPE.str.startswith('sPESOLTE')][~y2030_PEImp.sPE.str.startswith('sPESOLTH')][~y2030_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2030_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2030_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2030_PEImp.sPE.str.startswith('sPESWAST')][~y2030_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2030_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2030_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2030_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:12: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2030_PEImp = y2030_PEImp[~y2030_PEImp.sPE.str.startswith('sPEHYDRR')][~y2030_PEImp.sPE.str.startswith('sPEHYDRC')][~y2030_PEImp.sPE.str.startswith('sPEMNHY')][~y2030_PEImp.sPE.str.startswith('sPEWINON')][~y2030_PEImp.sPE.str.startswith('sPEWINOF')][~y2030_PEImp.sPE.str.startswith('sPESOLPV')][~y2030_PEImp.sPE.str.startswith('sPESOLTE')][~y2030_PEImp.sPE.str.startswith('sPESOLTH')][~y2030_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2030_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2030_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2030_PEImp.sPE.str.startswith('sPESWAST')][~y2030_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2030_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2030_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2030_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:12: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2030_PEImp = y2030_PEImp[~y2030_PEImp.sPE.str.startswith('sPEHYDRR')][~y2030_PEImp.sPE.str.startswith('sPEHYDRC')][~y2030_PEImp.sPE.str.startswith('sPEMNHY')][~y2030_PEImp.sPE.str.startswith('sPEWINON')][~y2030_PEImp.sPE.str.startswith('sPEWINOF')][~y2030_PEImp.sPE.str.startswith('sPESOLPV')][~y2030_PEImp.sPE.str.startswith('sPESOLTE')][~y2030_PEImp.sPE.str.startswith('sPESOLTH')][~y2030_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2030_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2030_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2030_PEImp.sPE.str.startswith('sPESWAST')][~y2030_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2030_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2030_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2030_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:13: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2035_PEImp = y2035_PEImp[~y2035_PEImp.sPE.str.startswith('sPEHYDRR')][~y2035_PEImp.sPE.str.startswith('sPEHYDRC')][~y2035_PEImp.sPE.str.startswith('sPEMNHY')][~y2035_PEImp.sPE.str.startswith('sPEWINON')][~y2035_PEImp.sPE.str.startswith('sPEWINOF')][~y2035_PEImp.sPE.str.startswith('sPESOLPV')][~y2035_PEImp.sPE.str.startswith('sPESOLTE')][~y2035_PEImp.sPE.str.startswith('sPESOLTH')][~y2035_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2035_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2035_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2035_PEImp.sPE.str.startswith('sPESWAST')][~y2035_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2035_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2035_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2035_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:13: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2035_PEImp = y2035_PEImp[~y2035_PEImp.sPE.str.startswith('sPEHYDRR')][~y2035_PEImp.sPE.str.startswith('sPEHYDRC')][~y2035_PEImp.sPE.str.startswith('sPEMNHY')][~y2035_PEImp.sPE.str.startswith('sPEWINON')][~y2035_PEImp.sPE.str.startswith('sPEWINOF')][~y2035_PEImp.sPE.str.startswith('sPESOLPV')][~y2035_PEImp.sPE.str.startswith('sPESOLTE')][~y2035_PEImp.sPE.str.startswith('sPESOLTH')][~y2035_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2035_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2035_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2035_PEImp.sPE.str.startswith('sPESWAST')][~y2035_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2035_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2035_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2035_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:13: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2035_PEImp = y2035_PEImp[~y2035_PEImp.sPE.str.startswith('sPEHYDRR')][~y2035_PEImp.sPE.str.startswith('sPEHYDRC')][~y2035_PEImp.sPE.str.startswith('sPEMNHY')][~y2035_PEImp.sPE.str.startswith('sPEWINON')][~y2035_PEImp.sPE.str.startswith('sPEWINOF')][~y2035_PEImp.sPE.str.startswith('sPESOLPV')][~y2035_PEImp.sPE.str.startswith('sPESOLTE')][~y2035_PEImp.sPE.str.startswith('sPESOLTH')][~y2035_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2035_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2035_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2035_PEImp.sPE.str.startswith('sPESWAST')][~y2035_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2035_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2035_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2035_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:13: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2035_PEImp = y2035_PEImp[~y2035_PEImp.sPE.str.startswith('sPEHYDRR')][~y2035_PEImp.sPE.str.startswith('sPEHYDRC')][~y2035_PEImp.sPE.str.startswith('sPEMNHY')][~y2035_PEImp.sPE.str.startswith('sPEWINON')][~y2035_PEImp.sPE.str.startswith('sPEWINOF')][~y2035_PEImp.sPE.str.startswith('sPESOLPV')][~y2035_PEImp.sPE.str.startswith('sPESOLTE')][~y2035_PEImp.sPE.str.startswith('sPESOLTH')][~y2035_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2035_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2035_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2035_PEImp.sPE.str.startswith('sPESWAST')][~y2035_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2035_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2035_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2035_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:13: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2035_PEImp = y2035_PEImp[~y2035_PEImp.sPE.str.startswith('sPEHYDRR')][~y2035_PEImp.sPE.str.startswith('sPEHYDRC')][~y2035_PEImp.sPE.str.startswith('sPEMNHY')][~y2035_PEImp.sPE.str.startswith('sPEWINON')][~y2035_PEImp.sPE.str.startswith('sPEWINOF')][~y2035_PEImp.sPE.str.startswith('sPESOLPV')][~y2035_PEImp.sPE.str.startswith('sPESOLTE')][~y2035_PEImp.sPE.str.startswith('sPESOLTH')][~y2035_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2035_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2035_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2035_PEImp.sPE.str.startswith('sPESWAST')][~y2035_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2035_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2035_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2035_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:13: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2035_PEImp = y2035_PEImp[~y2035_PEImp.sPE.str.startswith('sPEHYDRR')][~y2035_PEImp.sPE.str.startswith('sPEHYDRC')][~y2035_PEImp.sPE.str.startswith('sPEMNHY')][~y2035_PEImp.sPE.str.startswith('sPEWINON')][~y2035_PEImp.sPE.str.startswith('sPEWINOF')][~y2035_PEImp.sPE.str.startswith('sPESOLPV')][~y2035_PEImp.sPE.str.startswith('sPESOLTE')][~y2035_PEImp.sPE.str.startswith('sPESOLTH')][~y2035_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2035_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2035_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2035_PEImp.sPE.str.startswith('sPESWAST')][~y2035_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2035_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2035_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2035_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:13: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2035_PEImp = y2035_PEImp[~y2035_PEImp.sPE.str.startswith('sPEHYDRR')][~y2035_PEImp.sPE.str.startswith('sPEHYDRC')][~y2035_PEImp.sPE.str.startswith('sPEMNHY')][~y2035_PEImp.sPE.str.startswith('sPEWINON')][~y2035_PEImp.sPE.str.startswith('sPEWINOF')][~y2035_PEImp.sPE.str.startswith('sPESOLPV')][~y2035_PEImp.sPE.str.startswith('sPESOLTE')][~y2035_PEImp.sPE.str.startswith('sPESOLTH')][~y2035_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2035_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2035_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2035_PEImp.sPE.str.startswith('sPESWAST')][~y2035_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2035_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2035_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2035_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:13: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2035_PEImp = y2035_PEImp[~y2035_PEImp.sPE.str.startswith('sPEHYDRR')][~y2035_PEImp.sPE.str.startswith('sPEHYDRC')][~y2035_PEImp.sPE.str.startswith('sPEMNHY')][~y2035_PEImp.sPE.str.startswith('sPEWINON')][~y2035_PEImp.sPE.str.startswith('sPEWINOF')][~y2035_PEImp.sPE.str.startswith('sPESOLPV')][~y2035_PEImp.sPE.str.startswith('sPESOLTE')][~y2035_PEImp.sPE.str.startswith('sPESOLTH')][~y2035_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2035_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2035_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2035_PEImp.sPE.str.startswith('sPESWAST')][~y2035_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2035_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2035_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2035_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:13: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2035_PEImp = y2035_PEImp[~y2035_PEImp.sPE.str.startswith('sPEHYDRR')][~y2035_PEImp.sPE.str.startswith('sPEHYDRC')][~y2035_PEImp.sPE.str.startswith('sPEMNHY')][~y2035_PEImp.sPE.str.startswith('sPEWINON')][~y2035_PEImp.sPE.str.startswith('sPEWINOF')][~y2035_PEImp.sPE.str.startswith('sPESOLPV')][~y2035_PEImp.sPE.str.startswith('sPESOLTE')][~y2035_PEImp.sPE.str.startswith('sPESOLTH')][~y2035_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2035_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2035_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2035_PEImp.sPE.str.startswith('sPESWAST')][~y2035_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2035_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2035_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2035_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:13: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2035_PEImp = y2035_PEImp[~y2035_PEImp.sPE.str.startswith('sPEHYDRR')][~y2035_PEImp.sPE.str.startswith('sPEHYDRC')][~y2035_PEImp.sPE.str.startswith('sPEMNHY')][~y2035_PEImp.sPE.str.startswith('sPEWINON')][~y2035_PEImp.sPE.str.startswith('sPEWINOF')][~y2035_PEImp.sPE.str.startswith('sPESOLPV')][~y2035_PEImp.sPE.str.startswith('sPESOLTE')][~y2035_PEImp.sPE.str.startswith('sPESOLTH')][~y2035_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2035_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2035_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2035_PEImp.sPE.str.startswith('sPESWAST')][~y2035_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2035_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2035_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2035_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:13: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2035_PEImp = y2035_PEImp[~y2035_PEImp.sPE.str.startswith('sPEHYDRR')][~y2035_PEImp.sPE.str.startswith('sPEHYDRC')][~y2035_PEImp.sPE.str.startswith('sPEMNHY')][~y2035_PEImp.sPE.str.startswith('sPEWINON')][~y2035_PEImp.sPE.str.startswith('sPEWINOF')][~y2035_PEImp.sPE.str.startswith('sPESOLPV')][~y2035_PEImp.sPE.str.startswith('sPESOLTE')][~y2035_PEImp.sPE.str.startswith('sPESOLTH')][~y2035_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2035_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2035_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2035_PEImp.sPE.str.startswith('sPESWAST')][~y2035_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2035_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2035_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2035_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:13: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2035_PEImp = y2035_PEImp[~y2035_PEImp.sPE.str.startswith('sPEHYDRR')][~y2035_PEImp.sPE.str.startswith('sPEHYDRC')][~y2035_PEImp.sPE.str.startswith('sPEMNHY')][~y2035_PEImp.sPE.str.startswith('sPEWINON')][~y2035_PEImp.sPE.str.startswith('sPEWINOF')][~y2035_PEImp.sPE.str.startswith('sPESOLPV')][~y2035_PEImp.sPE.str.startswith('sPESOLTE')][~y2035_PEImp.sPE.str.startswith('sPESOLTH')][~y2035_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2035_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2035_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2035_PEImp.sPE.str.startswith('sPESWAST')][~y2035_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2035_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2035_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2035_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:13: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2035_PEImp = y2035_PEImp[~y2035_PEImp.sPE.str.startswith('sPEHYDRR')][~y2035_PEImp.sPE.str.startswith('sPEHYDRC')][~y2035_PEImp.sPE.str.startswith('sPEMNHY')][~y2035_PEImp.sPE.str.startswith('sPEWINON')][~y2035_PEImp.sPE.str.startswith('sPEWINOF')][~y2035_PEImp.sPE.str.startswith('sPESOLPV')][~y2035_PEImp.sPE.str.startswith('sPESOLTE')][~y2035_PEImp.sPE.str.startswith('sPESOLTH')][~y2035_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2035_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2035_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2035_PEImp.sPE.str.startswith('sPESWAST')][~y2035_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2035_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2035_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2035_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:13: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2035_PEImp = y2035_PEImp[~y2035_PEImp.sPE.str.startswith('sPEHYDRR')][~y2035_PEImp.sPE.str.startswith('sPEHYDRC')][~y2035_PEImp.sPE.str.startswith('sPEMNHY')][~y2035_PEImp.sPE.str.startswith('sPEWINON')][~y2035_PEImp.sPE.str.startswith('sPEWINOF')][~y2035_PEImp.sPE.str.startswith('sPESOLPV')][~y2035_PEImp.sPE.str.startswith('sPESOLTE')][~y2035_PEImp.sPE.str.startswith('sPESOLTH')][~y2035_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2035_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2035_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2035_PEImp.sPE.str.startswith('sPESWAST')][~y2035_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2035_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2035_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2035_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:13: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2035_PEImp = y2035_PEImp[~y2035_PEImp.sPE.str.startswith('sPEHYDRR')][~y2035_PEImp.sPE.str.startswith('sPEHYDRC')][~y2035_PEImp.sPE.str.startswith('sPEMNHY')][~y2035_PEImp.sPE.str.startswith('sPEWINON')][~y2035_PEImp.sPE.str.startswith('sPEWINOF')][~y2035_PEImp.sPE.str.startswith('sPESOLPV')][~y2035_PEImp.sPE.str.startswith('sPESOLTE')][~y2035_PEImp.sPE.str.startswith('sPESOLTH')][~y2035_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2035_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2035_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2035_PEImp.sPE.str.startswith('sPESWAST')][~y2035_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2035_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2035_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2035_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:14: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2040_PEImp = y2040_PEImp[~y2040_PEImp.sPE.str.startswith('sPEHYDRR')][~y2040_PEImp.sPE.str.startswith('sPEHYDRC')][~y2040_PEImp.sPE.str.startswith('sPEMNHY')][~y2040_PEImp.sPE.str.startswith('sPEWINON')][~y2040_PEImp.sPE.str.startswith('sPEWINOF')][~y2040_PEImp.sPE.str.startswith('sPESOLPV')][~y2040_PEImp.sPE.str.startswith('sPESOLTE')][~y2040_PEImp.sPE.str.startswith('sPESOLTH')][~y2040_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2040_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2040_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2040_PEImp.sPE.str.startswith('sPESWAST')][~y2040_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2040_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2040_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2040_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:14: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2040_PEImp = y2040_PEImp[~y2040_PEImp.sPE.str.startswith('sPEHYDRR')][~y2040_PEImp.sPE.str.startswith('sPEHYDRC')][~y2040_PEImp.sPE.str.startswith('sPEMNHY')][~y2040_PEImp.sPE.str.startswith('sPEWINON')][~y2040_PEImp.sPE.str.startswith('sPEWINOF')][~y2040_PEImp.sPE.str.startswith('sPESOLPV')][~y2040_PEImp.sPE.str.startswith('sPESOLTE')][~y2040_PEImp.sPE.str.startswith('sPESOLTH')][~y2040_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2040_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2040_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2040_PEImp.sPE.str.startswith('sPESWAST')][~y2040_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2040_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2040_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2040_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:14: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2040_PEImp = y2040_PEImp[~y2040_PEImp.sPE.str.startswith('sPEHYDRR')][~y2040_PEImp.sPE.str.startswith('sPEHYDRC')][~y2040_PEImp.sPE.str.startswith('sPEMNHY')][~y2040_PEImp.sPE.str.startswith('sPEWINON')][~y2040_PEImp.sPE.str.startswith('sPEWINOF')][~y2040_PEImp.sPE.str.startswith('sPESOLPV')][~y2040_PEImp.sPE.str.startswith('sPESOLTE')][~y2040_PEImp.sPE.str.startswith('sPESOLTH')][~y2040_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2040_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2040_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2040_PEImp.sPE.str.startswith('sPESWAST')][~y2040_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2040_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2040_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2040_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:14: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2040_PEImp = y2040_PEImp[~y2040_PEImp.sPE.str.startswith('sPEHYDRR')][~y2040_PEImp.sPE.str.startswith('sPEHYDRC')][~y2040_PEImp.sPE.str.startswith('sPEMNHY')][~y2040_PEImp.sPE.str.startswith('sPEWINON')][~y2040_PEImp.sPE.str.startswith('sPEWINOF')][~y2040_PEImp.sPE.str.startswith('sPESOLPV')][~y2040_PEImp.sPE.str.startswith('sPESOLTE')][~y2040_PEImp.sPE.str.startswith('sPESOLTH')][~y2040_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2040_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2040_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2040_PEImp.sPE.str.startswith('sPESWAST')][~y2040_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2040_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2040_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2040_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:14: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2040_PEImp = y2040_PEImp[~y2040_PEImp.sPE.str.startswith('sPEHYDRR')][~y2040_PEImp.sPE.str.startswith('sPEHYDRC')][~y2040_PEImp.sPE.str.startswith('sPEMNHY')][~y2040_PEImp.sPE.str.startswith('sPEWINON')][~y2040_PEImp.sPE.str.startswith('sPEWINOF')][~y2040_PEImp.sPE.str.startswith('sPESOLPV')][~y2040_PEImp.sPE.str.startswith('sPESOLTE')][~y2040_PEImp.sPE.str.startswith('sPESOLTH')][~y2040_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2040_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2040_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2040_PEImp.sPE.str.startswith('sPESWAST')][~y2040_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2040_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2040_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2040_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:14: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2040_PEImp = y2040_PEImp[~y2040_PEImp.sPE.str.startswith('sPEHYDRR')][~y2040_PEImp.sPE.str.startswith('sPEHYDRC')][~y2040_PEImp.sPE.str.startswith('sPEMNHY')][~y2040_PEImp.sPE.str.startswith('sPEWINON')][~y2040_PEImp.sPE.str.startswith('sPEWINOF')][~y2040_PEImp.sPE.str.startswith('sPESOLPV')][~y2040_PEImp.sPE.str.startswith('sPESOLTE')][~y2040_PEImp.sPE.str.startswith('sPESOLTH')][~y2040_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2040_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2040_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2040_PEImp.sPE.str.startswith('sPESWAST')][~y2040_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2040_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2040_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2040_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:14: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2040_PEImp = y2040_PEImp[~y2040_PEImp.sPE.str.startswith('sPEHYDRR')][~y2040_PEImp.sPE.str.startswith('sPEHYDRC')][~y2040_PEImp.sPE.str.startswith('sPEMNHY')][~y2040_PEImp.sPE.str.startswith('sPEWINON')][~y2040_PEImp.sPE.str.startswith('sPEWINOF')][~y2040_PEImp.sPE.str.startswith('sPESOLPV')][~y2040_PEImp.sPE.str.startswith('sPESOLTE')][~y2040_PEImp.sPE.str.startswith('sPESOLTH')][~y2040_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2040_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2040_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2040_PEImp.sPE.str.startswith('sPESWAST')][~y2040_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2040_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2040_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2040_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:14: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2040_PEImp = y2040_PEImp[~y2040_PEImp.sPE.str.startswith('sPEHYDRR')][~y2040_PEImp.sPE.str.startswith('sPEHYDRC')][~y2040_PEImp.sPE.str.startswith('sPEMNHY')][~y2040_PEImp.sPE.str.startswith('sPEWINON')][~y2040_PEImp.sPE.str.startswith('sPEWINOF')][~y2040_PEImp.sPE.str.startswith('sPESOLPV')][~y2040_PEImp.sPE.str.startswith('sPESOLTE')][~y2040_PEImp.sPE.str.startswith('sPESOLTH')][~y2040_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2040_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2040_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2040_PEImp.sPE.str.startswith('sPESWAST')][~y2040_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2040_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2040_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2040_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:14: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2040_PEImp = y2040_PEImp[~y2040_PEImp.sPE.str.startswith('sPEHYDRR')][~y2040_PEImp.sPE.str.startswith('sPEHYDRC')][~y2040_PEImp.sPE.str.startswith('sPEMNHY')][~y2040_PEImp.sPE.str.startswith('sPEWINON')][~y2040_PEImp.sPE.str.startswith('sPEWINOF')][~y2040_PEImp.sPE.str.startswith('sPESOLPV')][~y2040_PEImp.sPE.str.startswith('sPESOLTE')][~y2040_PEImp.sPE.str.startswith('sPESOLTH')][~y2040_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2040_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2040_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2040_PEImp.sPE.str.startswith('sPESWAST')][~y2040_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2040_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2040_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2040_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:14: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2040_PEImp = y2040_PEImp[~y2040_PEImp.sPE.str.startswith('sPEHYDRR')][~y2040_PEImp.sPE.str.startswith('sPEHYDRC')][~y2040_PEImp.sPE.str.startswith('sPEMNHY')][~y2040_PEImp.sPE.str.startswith('sPEWINON')][~y2040_PEImp.sPE.str.startswith('sPEWINOF')][~y2040_PEImp.sPE.str.startswith('sPESOLPV')][~y2040_PEImp.sPE.str.startswith('sPESOLTE')][~y2040_PEImp.sPE.str.startswith('sPESOLTH')][~y2040_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2040_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2040_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2040_PEImp.sPE.str.startswith('sPESWAST')][~y2040_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2040_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2040_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2040_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:14: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2040_PEImp = y2040_PEImp[~y2040_PEImp.sPE.str.startswith('sPEHYDRR')][~y2040_PEImp.sPE.str.startswith('sPEHYDRC')][~y2040_PEImp.sPE.str.startswith('sPEMNHY')][~y2040_PEImp.sPE.str.startswith('sPEWINON')][~y2040_PEImp.sPE.str.startswith('sPEWINOF')][~y2040_PEImp.sPE.str.startswith('sPESOLPV')][~y2040_PEImp.sPE.str.startswith('sPESOLTE')][~y2040_PEImp.sPE.str.startswith('sPESOLTH')][~y2040_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2040_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2040_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2040_PEImp.sPE.str.startswith('sPESWAST')][~y2040_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2040_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2040_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2040_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:14: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2040_PEImp = y2040_PEImp[~y2040_PEImp.sPE.str.startswith('sPEHYDRR')][~y2040_PEImp.sPE.str.startswith('sPEHYDRC')][~y2040_PEImp.sPE.str.startswith('sPEMNHY')][~y2040_PEImp.sPE.str.startswith('sPEWINON')][~y2040_PEImp.sPE.str.startswith('sPEWINOF')][~y2040_PEImp.sPE.str.startswith('sPESOLPV')][~y2040_PEImp.sPE.str.startswith('sPESOLTE')][~y2040_PEImp.sPE.str.startswith('sPESOLTH')][~y2040_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2040_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2040_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2040_PEImp.sPE.str.startswith('sPESWAST')][~y2040_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2040_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2040_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2040_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:14: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2040_PEImp = y2040_PEImp[~y2040_PEImp.sPE.str.startswith('sPEHYDRR')][~y2040_PEImp.sPE.str.startswith('sPEHYDRC')][~y2040_PEImp.sPE.str.startswith('sPEMNHY')][~y2040_PEImp.sPE.str.startswith('sPEWINON')][~y2040_PEImp.sPE.str.startswith('sPEWINOF')][~y2040_PEImp.sPE.str.startswith('sPESOLPV')][~y2040_PEImp.sPE.str.startswith('sPESOLTE')][~y2040_PEImp.sPE.str.startswith('sPESOLTH')][~y2040_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2040_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2040_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2040_PEImp.sPE.str.startswith('sPESWAST')][~y2040_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2040_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2040_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2040_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:14: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2040_PEImp = y2040_PEImp[~y2040_PEImp.sPE.str.startswith('sPEHYDRR')][~y2040_PEImp.sPE.str.startswith('sPEHYDRC')][~y2040_PEImp.sPE.str.startswith('sPEMNHY')][~y2040_PEImp.sPE.str.startswith('sPEWINON')][~y2040_PEImp.sPE.str.startswith('sPEWINOF')][~y2040_PEImp.sPE.str.startswith('sPESOLPV')][~y2040_PEImp.sPE.str.startswith('sPESOLTE')][~y2040_PEImp.sPE.str.startswith('sPESOLTH')][~y2040_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2040_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2040_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2040_PEImp.sPE.str.startswith('sPESWAST')][~y2040_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2040_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2040_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2040_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:14: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2040_PEImp = y2040_PEImp[~y2040_PEImp.sPE.str.startswith('sPEHYDRR')][~y2040_PEImp.sPE.str.startswith('sPEHYDRC')][~y2040_PEImp.sPE.str.startswith('sPEMNHY')][~y2040_PEImp.sPE.str.startswith('sPEWINON')][~y2040_PEImp.sPE.str.startswith('sPEWINOF')][~y2040_PEImp.sPE.str.startswith('sPESOLPV')][~y2040_PEImp.sPE.str.startswith('sPESOLTE')][~y2040_PEImp.sPE.str.startswith('sPESOLTH')][~y2040_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2040_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2040_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2040_PEImp.sPE.str.startswith('sPESWAST')][~y2040_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2040_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2040_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2040_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:15: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2045_PEImp = y2045_PEImp[~y2045_PEImp.sPE.str.startswith('sPEHYDRR')][~y2045_PEImp.sPE.str.startswith('sPEHYDRC')][~y2045_PEImp.sPE.str.startswith('sPEMNHY')][~y2045_PEImp.sPE.str.startswith('sPEWINON')][~y2045_PEImp.sPE.str.startswith('sPEWINOF')][~y2045_PEImp.sPE.str.startswith('sPESOLPV')][~y2045_PEImp.sPE.str.startswith('sPESOLTE')][~y2045_PEImp.sPE.str.startswith('sPESOLTH')][~y2045_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2045_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2045_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2045_PEImp.sPE.str.startswith('sPESWAST')][~y2045_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2045_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2045_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2045_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:15: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2045_PEImp = y2045_PEImp[~y2045_PEImp.sPE.str.startswith('sPEHYDRR')][~y2045_PEImp.sPE.str.startswith('sPEHYDRC')][~y2045_PEImp.sPE.str.startswith('sPEMNHY')][~y2045_PEImp.sPE.str.startswith('sPEWINON')][~y2045_PEImp.sPE.str.startswith('sPEWINOF')][~y2045_PEImp.sPE.str.startswith('sPESOLPV')][~y2045_PEImp.sPE.str.startswith('sPESOLTE')][~y2045_PEImp.sPE.str.startswith('sPESOLTH')][~y2045_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2045_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2045_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2045_PEImp.sPE.str.startswith('sPESWAST')][~y2045_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2045_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2045_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2045_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:15: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2045_PEImp = y2045_PEImp[~y2045_PEImp.sPE.str.startswith('sPEHYDRR')][~y2045_PEImp.sPE.str.startswith('sPEHYDRC')][~y2045_PEImp.sPE.str.startswith('sPEMNHY')][~y2045_PEImp.sPE.str.startswith('sPEWINON')][~y2045_PEImp.sPE.str.startswith('sPEWINOF')][~y2045_PEImp.sPE.str.startswith('sPESOLPV')][~y2045_PEImp.sPE.str.startswith('sPESOLTE')][~y2045_PEImp.sPE.str.startswith('sPESOLTH')][~y2045_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2045_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2045_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2045_PEImp.sPE.str.startswith('sPESWAST')][~y2045_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2045_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2045_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2045_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:15: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2045_PEImp = y2045_PEImp[~y2045_PEImp.sPE.str.startswith('sPEHYDRR')][~y2045_PEImp.sPE.str.startswith('sPEHYDRC')][~y2045_PEImp.sPE.str.startswith('sPEMNHY')][~y2045_PEImp.sPE.str.startswith('sPEWINON')][~y2045_PEImp.sPE.str.startswith('sPEWINOF')][~y2045_PEImp.sPE.str.startswith('sPESOLPV')][~y2045_PEImp.sPE.str.startswith('sPESOLTE')][~y2045_PEImp.sPE.str.startswith('sPESOLTH')][~y2045_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2045_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2045_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2045_PEImp.sPE.str.startswith('sPESWAST')][~y2045_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2045_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2045_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2045_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:15: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2045_PEImp = y2045_PEImp[~y2045_PEImp.sPE.str.startswith('sPEHYDRR')][~y2045_PEImp.sPE.str.startswith('sPEHYDRC')][~y2045_PEImp.sPE.str.startswith('sPEMNHY')][~y2045_PEImp.sPE.str.startswith('sPEWINON')][~y2045_PEImp.sPE.str.startswith('sPEWINOF')][~y2045_PEImp.sPE.str.startswith('sPESOLPV')][~y2045_PEImp.sPE.str.startswith('sPESOLTE')][~y2045_PEImp.sPE.str.startswith('sPESOLTH')][~y2045_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2045_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2045_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2045_PEImp.sPE.str.startswith('sPESWAST')][~y2045_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2045_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2045_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2045_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:15: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2045_PEImp = y2045_PEImp[~y2045_PEImp.sPE.str.startswith('sPEHYDRR')][~y2045_PEImp.sPE.str.startswith('sPEHYDRC')][~y2045_PEImp.sPE.str.startswith('sPEMNHY')][~y2045_PEImp.sPE.str.startswith('sPEWINON')][~y2045_PEImp.sPE.str.startswith('sPEWINOF')][~y2045_PEImp.sPE.str.startswith('sPESOLPV')][~y2045_PEImp.sPE.str.startswith('sPESOLTE')][~y2045_PEImp.sPE.str.startswith('sPESOLTH')][~y2045_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2045_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2045_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2045_PEImp.sPE.str.startswith('sPESWAST')][~y2045_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2045_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2045_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2045_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:15: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2045_PEImp = y2045_PEImp[~y2045_PEImp.sPE.str.startswith('sPEHYDRR')][~y2045_PEImp.sPE.str.startswith('sPEHYDRC')][~y2045_PEImp.sPE.str.startswith('sPEMNHY')][~y2045_PEImp.sPE.str.startswith('sPEWINON')][~y2045_PEImp.sPE.str.startswith('sPEWINOF')][~y2045_PEImp.sPE.str.startswith('sPESOLPV')][~y2045_PEImp.sPE.str.startswith('sPESOLTE')][~y2045_PEImp.sPE.str.startswith('sPESOLTH')][~y2045_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2045_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2045_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2045_PEImp.sPE.str.startswith('sPESWAST')][~y2045_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2045_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2045_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2045_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:15: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2045_PEImp = y2045_PEImp[~y2045_PEImp.sPE.str.startswith('sPEHYDRR')][~y2045_PEImp.sPE.str.startswith('sPEHYDRC')][~y2045_PEImp.sPE.str.startswith('sPEMNHY')][~y2045_PEImp.sPE.str.startswith('sPEWINON')][~y2045_PEImp.sPE.str.startswith('sPEWINOF')][~y2045_PEImp.sPE.str.startswith('sPESOLPV')][~y2045_PEImp.sPE.str.startswith('sPESOLTE')][~y2045_PEImp.sPE.str.startswith('sPESOLTH')][~y2045_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2045_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2045_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2045_PEImp.sPE.str.startswith('sPESWAST')][~y2045_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2045_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2045_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2045_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:15: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2045_PEImp = y2045_PEImp[~y2045_PEImp.sPE.str.startswith('sPEHYDRR')][~y2045_PEImp.sPE.str.startswith('sPEHYDRC')][~y2045_PEImp.sPE.str.startswith('sPEMNHY')][~y2045_PEImp.sPE.str.startswith('sPEWINON')][~y2045_PEImp.sPE.str.startswith('sPEWINOF')][~y2045_PEImp.sPE.str.startswith('sPESOLPV')][~y2045_PEImp.sPE.str.startswith('sPESOLTE')][~y2045_PEImp.sPE.str.startswith('sPESOLTH')][~y2045_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2045_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2045_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2045_PEImp.sPE.str.startswith('sPESWAST')][~y2045_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2045_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2045_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2045_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:15: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2045_PEImp = y2045_PEImp[~y2045_PEImp.sPE.str.startswith('sPEHYDRR')][~y2045_PEImp.sPE.str.startswith('sPEHYDRC')][~y2045_PEImp.sPE.str.startswith('sPEMNHY')][~y2045_PEImp.sPE.str.startswith('sPEWINON')][~y2045_PEImp.sPE.str.startswith('sPEWINOF')][~y2045_PEImp.sPE.str.startswith('sPESOLPV')][~y2045_PEImp.sPE.str.startswith('sPESOLTE')][~y2045_PEImp.sPE.str.startswith('sPESOLTH')][~y2045_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2045_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2045_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2045_PEImp.sPE.str.startswith('sPESWAST')][~y2045_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2045_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2045_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2045_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:15: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2045_PEImp = y2045_PEImp[~y2045_PEImp.sPE.str.startswith('sPEHYDRR')][~y2045_PEImp.sPE.str.startswith('sPEHYDRC')][~y2045_PEImp.sPE.str.startswith('sPEMNHY')][~y2045_PEImp.sPE.str.startswith('sPEWINON')][~y2045_PEImp.sPE.str.startswith('sPEWINOF')][~y2045_PEImp.sPE.str.startswith('sPESOLPV')][~y2045_PEImp.sPE.str.startswith('sPESOLTE')][~y2045_PEImp.sPE.str.startswith('sPESOLTH')][~y2045_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2045_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2045_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2045_PEImp.sPE.str.startswith('sPESWAST')][~y2045_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2045_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2045_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2045_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:15: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2045_PEImp = y2045_PEImp[~y2045_PEImp.sPE.str.startswith('sPEHYDRR')][~y2045_PEImp.sPE.str.startswith('sPEHYDRC')][~y2045_PEImp.sPE.str.startswith('sPEMNHY')][~y2045_PEImp.sPE.str.startswith('sPEWINON')][~y2045_PEImp.sPE.str.startswith('sPEWINOF')][~y2045_PEImp.sPE.str.startswith('sPESOLPV')][~y2045_PEImp.sPE.str.startswith('sPESOLTE')][~y2045_PEImp.sPE.str.startswith('sPESOLTH')][~y2045_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2045_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2045_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2045_PEImp.sPE.str.startswith('sPESWAST')][~y2045_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2045_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2045_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2045_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:15: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2045_PEImp = y2045_PEImp[~y2045_PEImp.sPE.str.startswith('sPEHYDRR')][~y2045_PEImp.sPE.str.startswith('sPEHYDRC')][~y2045_PEImp.sPE.str.startswith('sPEMNHY')][~y2045_PEImp.sPE.str.startswith('sPEWINON')][~y2045_PEImp.sPE.str.startswith('sPEWINOF')][~y2045_PEImp.sPE.str.startswith('sPESOLPV')][~y2045_PEImp.sPE.str.startswith('sPESOLTE')][~y2045_PEImp.sPE.str.startswith('sPESOLTH')][~y2045_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2045_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2045_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2045_PEImp.sPE.str.startswith('sPESWAST')][~y2045_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2045_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2045_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2045_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:15: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2045_PEImp = y2045_PEImp[~y2045_PEImp.sPE.str.startswith('sPEHYDRR')][~y2045_PEImp.sPE.str.startswith('sPEHYDRC')][~y2045_PEImp.sPE.str.startswith('sPEMNHY')][~y2045_PEImp.sPE.str.startswith('sPEWINON')][~y2045_PEImp.sPE.str.startswith('sPEWINOF')][~y2045_PEImp.sPE.str.startswith('sPESOLPV')][~y2045_PEImp.sPE.str.startswith('sPESOLTE')][~y2045_PEImp.sPE.str.startswith('sPESOLTH')][~y2045_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2045_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2045_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2045_PEImp.sPE.str.startswith('sPESWAST')][~y2045_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2045_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2045_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2045_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:15: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2045_PEImp = y2045_PEImp[~y2045_PEImp.sPE.str.startswith('sPEHYDRR')][~y2045_PEImp.sPE.str.startswith('sPEHYDRC')][~y2045_PEImp.sPE.str.startswith('sPEMNHY')][~y2045_PEImp.sPE.str.startswith('sPEWINON')][~y2045_PEImp.sPE.str.startswith('sPEWINOF')][~y2045_PEImp.sPE.str.startswith('sPESOLPV')][~y2045_PEImp.sPE.str.startswith('sPESOLTE')][~y2045_PEImp.sPE.str.startswith('sPESOLTH')][~y2045_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2045_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2045_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2045_PEImp.sPE.str.startswith('sPESWAST')][~y2045_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2045_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2045_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2045_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:16: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2050_PEImp = y2050_PEImp[~y2050_PEImp.sPE.str.startswith('sPEHYDRR')][~y2050_PEImp.sPE.str.startswith('sPEHYDRC')][~y2050_PEImp.sPE.str.startswith('sPEMNHY')][~y2050_PEImp.sPE.str.startswith('sPEWINON')][~y2050_PEImp.sPE.str.startswith('sPEWINOF')][~y2050_PEImp.sPE.str.startswith('sPESOLPV')][~y2050_PEImp.sPE.str.startswith('sPESOLTE')][~y2050_PEImp.sPE.str.startswith('sPESOLTH')][~y2050_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2050_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2050_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2050_PEImp.sPE.str.startswith('sPESWAST')][~y2050_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2050_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2050_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2050_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:16: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2050_PEImp = y2050_PEImp[~y2050_PEImp.sPE.str.startswith('sPEHYDRR')][~y2050_PEImp.sPE.str.startswith('sPEHYDRC')][~y2050_PEImp.sPE.str.startswith('sPEMNHY')][~y2050_PEImp.sPE.str.startswith('sPEWINON')][~y2050_PEImp.sPE.str.startswith('sPEWINOF')][~y2050_PEImp.sPE.str.startswith('sPESOLPV')][~y2050_PEImp.sPE.str.startswith('sPESOLTE')][~y2050_PEImp.sPE.str.startswith('sPESOLTH')][~y2050_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2050_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2050_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2050_PEImp.sPE.str.startswith('sPESWAST')][~y2050_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2050_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2050_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2050_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:16: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2050_PEImp = y2050_PEImp[~y2050_PEImp.sPE.str.startswith('sPEHYDRR')][~y2050_PEImp.sPE.str.startswith('sPEHYDRC')][~y2050_PEImp.sPE.str.startswith('sPEMNHY')][~y2050_PEImp.sPE.str.startswith('sPEWINON')][~y2050_PEImp.sPE.str.startswith('sPEWINOF')][~y2050_PEImp.sPE.str.startswith('sPESOLPV')][~y2050_PEImp.sPE.str.startswith('sPESOLTE')][~y2050_PEImp.sPE.str.startswith('sPESOLTH')][~y2050_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2050_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2050_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2050_PEImp.sPE.str.startswith('sPESWAST')][~y2050_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2050_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2050_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2050_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:16: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2050_PEImp = y2050_PEImp[~y2050_PEImp.sPE.str.startswith('sPEHYDRR')][~y2050_PEImp.sPE.str.startswith('sPEHYDRC')][~y2050_PEImp.sPE.str.startswith('sPEMNHY')][~y2050_PEImp.sPE.str.startswith('sPEWINON')][~y2050_PEImp.sPE.str.startswith('sPEWINOF')][~y2050_PEImp.sPE.str.startswith('sPESOLPV')][~y2050_PEImp.sPE.str.startswith('sPESOLTE')][~y2050_PEImp.sPE.str.startswith('sPESOLTH')][~y2050_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2050_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2050_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2050_PEImp.sPE.str.startswith('sPESWAST')][~y2050_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2050_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2050_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2050_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:16: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2050_PEImp = y2050_PEImp[~y2050_PEImp.sPE.str.startswith('sPEHYDRR')][~y2050_PEImp.sPE.str.startswith('sPEHYDRC')][~y2050_PEImp.sPE.str.startswith('sPEMNHY')][~y2050_PEImp.sPE.str.startswith('sPEWINON')][~y2050_PEImp.sPE.str.startswith('sPEWINOF')][~y2050_PEImp.sPE.str.startswith('sPESOLPV')][~y2050_PEImp.sPE.str.startswith('sPESOLTE')][~y2050_PEImp.sPE.str.startswith('sPESOLTH')][~y2050_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2050_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2050_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2050_PEImp.sPE.str.startswith('sPESWAST')][~y2050_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2050_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2050_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2050_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:16: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2050_PEImp = y2050_PEImp[~y2050_PEImp.sPE.str.startswith('sPEHYDRR')][~y2050_PEImp.sPE.str.startswith('sPEHYDRC')][~y2050_PEImp.sPE.str.startswith('sPEMNHY')][~y2050_PEImp.sPE.str.startswith('sPEWINON')][~y2050_PEImp.sPE.str.startswith('sPEWINOF')][~y2050_PEImp.sPE.str.startswith('sPESOLPV')][~y2050_PEImp.sPE.str.startswith('sPESOLTE')][~y2050_PEImp.sPE.str.startswith('sPESOLTH')][~y2050_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2050_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2050_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2050_PEImp.sPE.str.startswith('sPESWAST')][~y2050_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2050_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2050_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2050_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:16: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2050_PEImp = y2050_PEImp[~y2050_PEImp.sPE.str.startswith('sPEHYDRR')][~y2050_PEImp.sPE.str.startswith('sPEHYDRC')][~y2050_PEImp.sPE.str.startswith('sPEMNHY')][~y2050_PEImp.sPE.str.startswith('sPEWINON')][~y2050_PEImp.sPE.str.startswith('sPEWINOF')][~y2050_PEImp.sPE.str.startswith('sPESOLPV')][~y2050_PEImp.sPE.str.startswith('sPESOLTE')][~y2050_PEImp.sPE.str.startswith('sPESOLTH')][~y2050_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2050_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2050_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2050_PEImp.sPE.str.startswith('sPESWAST')][~y2050_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2050_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2050_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2050_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:16: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2050_PEImp = y2050_PEImp[~y2050_PEImp.sPE.str.startswith('sPEHYDRR')][~y2050_PEImp.sPE.str.startswith('sPEHYDRC')][~y2050_PEImp.sPE.str.startswith('sPEMNHY')][~y2050_PEImp.sPE.str.startswith('sPEWINON')][~y2050_PEImp.sPE.str.startswith('sPEWINOF')][~y2050_PEImp.sPE.str.startswith('sPESOLPV')][~y2050_PEImp.sPE.str.startswith('sPESOLTE')][~y2050_PEImp.sPE.str.startswith('sPESOLTH')][~y2050_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2050_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2050_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2050_PEImp.sPE.str.startswith('sPESWAST')][~y2050_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2050_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2050_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2050_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:16: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2050_PEImp = y2050_PEImp[~y2050_PEImp.sPE.str.startswith('sPEHYDRR')][~y2050_PEImp.sPE.str.startswith('sPEHYDRC')][~y2050_PEImp.sPE.str.startswith('sPEMNHY')][~y2050_PEImp.sPE.str.startswith('sPEWINON')][~y2050_PEImp.sPE.str.startswith('sPEWINOF')][~y2050_PEImp.sPE.str.startswith('sPESOLPV')][~y2050_PEImp.sPE.str.startswith('sPESOLTE')][~y2050_PEImp.sPE.str.startswith('sPESOLTH')][~y2050_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2050_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2050_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2050_PEImp.sPE.str.startswith('sPESWAST')][~y2050_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2050_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2050_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2050_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:16: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2050_PEImp = y2050_PEImp[~y2050_PEImp.sPE.str.startswith('sPEHYDRR')][~y2050_PEImp.sPE.str.startswith('sPEHYDRC')][~y2050_PEImp.sPE.str.startswith('sPEMNHY')][~y2050_PEImp.sPE.str.startswith('sPEWINON')][~y2050_PEImp.sPE.str.startswith('sPEWINOF')][~y2050_PEImp.sPE.str.startswith('sPESOLPV')][~y2050_PEImp.sPE.str.startswith('sPESOLTE')][~y2050_PEImp.sPE.str.startswith('sPESOLTH')][~y2050_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2050_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2050_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2050_PEImp.sPE.str.startswith('sPESWAST')][~y2050_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2050_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2050_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2050_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:16: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2050_PEImp = y2050_PEImp[~y2050_PEImp.sPE.str.startswith('sPEHYDRR')][~y2050_PEImp.sPE.str.startswith('sPEHYDRC')][~y2050_PEImp.sPE.str.startswith('sPEMNHY')][~y2050_PEImp.sPE.str.startswith('sPEWINON')][~y2050_PEImp.sPE.str.startswith('sPEWINOF')][~y2050_PEImp.sPE.str.startswith('sPESOLPV')][~y2050_PEImp.sPE.str.startswith('sPESOLTE')][~y2050_PEImp.sPE.str.startswith('sPESOLTH')][~y2050_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2050_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2050_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2050_PEImp.sPE.str.startswith('sPESWAST')][~y2050_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2050_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2050_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2050_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:16: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2050_PEImp = y2050_PEImp[~y2050_PEImp.sPE.str.startswith('sPEHYDRR')][~y2050_PEImp.sPE.str.startswith('sPEHYDRC')][~y2050_PEImp.sPE.str.startswith('sPEMNHY')][~y2050_PEImp.sPE.str.startswith('sPEWINON')][~y2050_PEImp.sPE.str.startswith('sPEWINOF')][~y2050_PEImp.sPE.str.startswith('sPESOLPV')][~y2050_PEImp.sPE.str.startswith('sPESOLTE')][~y2050_PEImp.sPE.str.startswith('sPESOLTH')][~y2050_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2050_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2050_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2050_PEImp.sPE.str.startswith('sPESWAST')][~y2050_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2050_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2050_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2050_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:16: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2050_PEImp = y2050_PEImp[~y2050_PEImp.sPE.str.startswith('sPEHYDRR')][~y2050_PEImp.sPE.str.startswith('sPEHYDRC')][~y2050_PEImp.sPE.str.startswith('sPEMNHY')][~y2050_PEImp.sPE.str.startswith('sPEWINON')][~y2050_PEImp.sPE.str.startswith('sPEWINOF')][~y2050_PEImp.sPE.str.startswith('sPESOLPV')][~y2050_PEImp.sPE.str.startswith('sPESOLTE')][~y2050_PEImp.sPE.str.startswith('sPESOLTH')][~y2050_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2050_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2050_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2050_PEImp.sPE.str.startswith('sPESWAST')][~y2050_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2050_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2050_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2050_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:16: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2050_PEImp = y2050_PEImp[~y2050_PEImp.sPE.str.startswith('sPEHYDRR')][~y2050_PEImp.sPE.str.startswith('sPEHYDRC')][~y2050_PEImp.sPE.str.startswith('sPEMNHY')][~y2050_PEImp.sPE.str.startswith('sPEWINON')][~y2050_PEImp.sPE.str.startswith('sPEWINOF')][~y2050_PEImp.sPE.str.startswith('sPESOLPV')][~y2050_PEImp.sPE.str.startswith('sPESOLTE')][~y2050_PEImp.sPE.str.startswith('sPESOLTH')][~y2050_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2050_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2050_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2050_PEImp.sPE.str.startswith('sPESWAST')][~y2050_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2050_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2050_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2050_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:16: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2050_PEImp = y2050_PEImp[~y2050_PEImp.sPE.str.startswith('sPEHYDRR')][~y2050_PEImp.sPE.str.startswith('sPEHYDRC')][~y2050_PEImp.sPE.str.startswith('sPEMNHY')][~y2050_PEImp.sPE.str.startswith('sPEWINON')][~y2050_PEImp.sPE.str.startswith('sPEWINOF')][~y2050_PEImp.sPE.str.startswith('sPESOLPV')][~y2050_PEImp.sPE.str.startswith('sPESOLTE')][~y2050_PEImp.sPE.str.startswith('sPESOLTH')][~y2050_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2050_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2050_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2050_PEImp.sPE.str.startswith('sPESWAST')][~y2050_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2050_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2050_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2050_PEImp.sPE.str.startswith('sPEHUMANE')]\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_42580\\1526215219.py:46: UserWarning: No artists with labels found to put in legend. Note that artists whose label start with an underscore are ignored when legend() is called with no argument.\n", + " plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABPkAAAVYCAYAAADV7g3+AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdeVhUZfsH8O/MsAw7KCqiAioKpLhW7luhkEu+Lrnh65Jbmqml5ZIpmVppqG0qvqHp+xPNtEV9jSwVxa1ywVIUd3HBNBWQHWbO7w9mDhxmgBm24ej3c11zFWeb5wyiN/e57+dRCIIggIiIiIiIiIiIiGRLaekBEBERERERERERUfkwyUdERERERERERCRzTPIRERERERERERHJHJN8REREREREREREMsckHxERERERERERkcwxyUdERERERERERCRzTPIRERERERERERHJHJN8REREREREREREMsckHxERERERERERkcwxyUdERE88Hx8fKBQKycvW1hZeXl4YOnQoYmNjy3TdMWPGQKFQ4Ouvv67YAT8B9J9Naa8xY8ZYeqiyof9M+ZlVjPPnz+Ott95C69atUbNmTVhbW6NmzZro0KED5s6di/Pnz1t6iFUiLCwMCoUCYWFhlh4KERERlZOVpQdARERUVTp16gRfX18AQHJyMk6cOIFt27bh22+/xSeffIK33nrLwiN88jRu3BidO3cudn9J+4iKCgsLw/vvv4+FCxeWOSmVl5eHt99+G5999hm0Wi1q1KiB5557DjVr1kRycjJOnjyJ48ePY9myZfj0008xderUir0JmYiJiUGPHj3QrVs3xMTEWHo4REREZAIm+YiI6Kkxfvx4SRVUVlYWJk2ahE2bNuGdd95B37590bRpU5Ov9+GHH2LOnDmoW7duJYz2ydC5c2dWOlK1MnLkSHzzzTdwdnbGp59+in//+99QqVTifkEQ8Msvv2Du3Lm4fPmyBUdaNaZOnYphw4bB3d3d0kMhIiKicmK7LhERPbXUajW+/PJLODg4QKPR4LvvvjPr/Lp168Lf3x8uLi6VNEIiqkjr16/HN998A2tra+zduxdjxoyRJPgAQKFQoFevXjh+/DiGDh1qoZFWHXd3d/j7+zPJR0RE9ARgko+IiJ5qjo6O8PPzAwBcv35d3K6fMw4ANmzYgA4dOsDFxQUKhUI8rrg5+QrPcXXn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IiIiIiIiIpljko+IiIiIiIiIiEjmmOQjIiIiIiIiIiKSOSb5iIiIiIiIiIiIZI5JPiIiIiIiIiIiIpljko+IiIiIiIiIiEjmmOQjIiIiIiIiIiKSOSb5iIiIiIiIiIiIZI5JPiIiIiIiIiIiIpljko+IiIiIiIiIiEjmmOQjIiIiIiIiIiKSOSb5iIiIiIiIiIiIZI5JPiIiIiIiIiIiIpljko+IiIiIiIiIiEjmmOQjIiIiIiIiIiKSOSb5iIiIiIiIiIiIZI5JPiIiIiIiIiIiIpljko+IiIiIiIiIiEjmmOQjIiIiIiIiIiKSOSb5iIiIiIiIiIiIZI5JPiIiIiIiIiIiIpljko+IiIiIiIiIiEjmmOQjIiIiIiIiIiKSOSb5iIiIiIiIiIiIZI5JPiIiIiIiIiIiIpljko+IiIiIiIiIiEjmmOQjIiIiIiIiIiKSOSb5iIiIiIiIiIiIZI5JPiIiIiIiIiIiIpljko+IiIiIiIiIiEjmmOQjIiIiIiIiIiKSOSb5iIiIiIiIiIiIZI5JPiIiIiIiIiIiIpljko+IiIiIiIiIiEjmmOQjIiIiIiIiIiKSOSb5iIiIiIiIiIiIZI5JPiIiIiIiIiIiIpljko+IiIiIiIiIiEjmmOQjIiIiIiIiIiKSOSb5iIiIiIiIiIiIZI5JPiIiIiIiIiIiIpljko+IiIiIiIiIiEjmmOQjIiIiIiIiIiKSOSb5iIiIiIiIiIiIZI5JPiIiIiIiIiIiIpljko+IiIiIiIiIiEjmmOQjIiIiIiIiIiKSOSb5iIiIiIiIiIiIZI5JPiIiIiIiIiIiIpljko+IiIiIiIiIiEjmmOQjIiIiIiIiIiKSOSb5iIiIiIiIiIiIZI5JPiIiIiIiIiIiIpljko+IiIiIiIiIiEjmmOQjIiIiIiIiIiKSOSb5iIiIiIiIiIiIZI5JPiIiIiIiIiIiIpljko+IiIiIiIiIiEjmmOQjIiIiIiIiIiKSOSb5iIiIiIiIiIiIZI5JPiIiIiIiIiIiIpljko+IiIiIiIiIiEjmmOQjIiIiIiIiIiKSOSb5iIiIiIiIiIiIZI5JPiIiIiIiIiIiIpljko+IiIiIiIiIiEjmmOQjIiIiIiIiIiKSOSb5iIiIiIiIiIiIZI5JPiIiIiIiIiIiIpljko+IiIiIiIiIiEjmmOQjIiIiIiIiIiKS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d++OgwcPFru/8F9p586dw1tvvYXDhw/DxsYGffr0QXh4OOrUqSMeM2bMGGzcuLHY6127dg0+Pj7i17du3cKbb76JvXv3QqvVonv37li5ciV8fX3Ld2NERERETzlLxnkTJkzA0aNHcfPmTWRlZcHb2xuDBg3Cu+++yylZiEg2mOQjIiIiIiIiIiKSOc7JR0REREREREREJHNM8hEREREREREREckck3xEREREREREREQyxyQfERERERERERGRzDHJR0REREREREREJHNM8hEREREREREREcmclaUHUNm0Wi3u3LkDJycnKBQKSw+HiIiIZEAQBDx+/Bienp5QKvlMtLpinEdERETmepLjvCc+yXfnzh00aNDA0sMgIiIiGbp58ybq169v6WFQMRjnERERUVk9iXHeE5/kc3JyApD/zXN2drbwaIiIiEgOUlNT0aBBAzGOoOqJcR4RERGZ60mO8574JJ++dcPZ2ZnBHxEREZmFLaDVG+M8IiIiKqsnMc57spqPiYiIiIiIiIiInkJM8hEREREREREREckck3xEREREREREREQy98TPyVcaQRCQl5cHjUZj6aEQVWsqlQpWVlZP5LwFRET05NJoNMjNzbX0MIiqNcZ5RERPhqc6yZeTk4OkpCRkZGRYeihEsmBvb4+6devCxsbG0kMhIiIqVVpaGm7dugVBECw9FKJqj3EeEZH8PbVJPq1Wi2vXrkGlUsHT0xM2NjZ8ckVUDEEQkJOTg/v37+PatWto0qQJlEp2+xMRUfWl0Whw69Yt2Nvbo1atWozziIrBOI+I6Mnx1Cb5cnJyoNVq0aBBA9jb21t6OETVnp2dHaytrXHjxg3k5ORArVZbekhERETFys3NhSAIqFWrFuzs7Cw9HKJqjXEeEdGT4alN8unxKRWR6fjzQlR57i5ZipzEG2iwejUUKpWlh1NmOTdv4taU15H36JFku0KlgvvU1+H2yisWGhk9rVjBR2QaxnlEVBZpsYdx/7PP4PTii3B/bZKlh/PUe+qTfERERJYm5OTg0f/9HyAIyL15EzY+PpYeUpmlxRxE9qVLRvclb9/OJB8RERHREyDv0SPc++gjpPy4EwCgSU5mkq8aYJKPiIjIwnLv3QN0CwNoMzMtPJry0Tx6CABw7t0bNSflB3rZCRdw553Z0DxKtuDIiIiIiKi8BEFA6u7d+Hvph9AU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1q1zmxedTid++OEHIURg5mXWrFli2rRpYsOGDeLw4cNix44dYtKkScJoNLp1bq7LnXfeKTIzM8X69evFrl27xNVXXy2ioqKU7q1CCDF37lwRFxcnvvjiC7Fz505xzTXXiDZt2giTyaRsc+zYMZGTkyOeeuopERUVpczJTz/95PV5RO7e6noeefzxx0WrVq2U80hBQYHIyckR27ZtUz7Xli9fLpYuXSqSk5PFww8/LK6++mrRqlUr8dBDD4nFixeLLVu2iA0bNoh7771XOY+UlpYKo9EoZs2aVe+5kLVu3VpER0eLO++80+32Nm3aiOjoaHH77bf7vM+Gnp/i4mKvx+Kpm/X8+fNFZmam8n1dP9sWi0W0b99eXHrppWLr1q3i4MGD4oUXXhCSJImvv/5a2Y88P/IxQ81HXT9DEyZMEI8++qiyvTfncgosX+do7ty5QqfTiU8//dTtusCXzx/yna/zVBW76zYOX+fp999/F9HR0eLee+8V+/btE1999ZVISUkRs2fPDtZLaPJ8naNZs2aJ6Oho8eGHH4rDhw+LtWvXinbt2onx48cH6yU0C8XFxcrvtwDESy+9JHJycsSxY8eEEEI8+uijYsKECcr2hw8fFhEREWLatGli7969yvX4mjVrgvUS/OZTkE8IZ8voN998s9rthw4dEgDEvHnz3G7fsGGDAODx68iRI8p2R48eFVdddZUwGo0iKSlJ/OMf/xBWq1W5/5///Kdo166dMBgMIiEhQQwZMkR8//331cbx2muvidatWwudTif69esnfvrpJ7f7J06cKAYPHlzj6/MmoJSZmSlmzZpV4/1CCPHss8+KpKQkERUVJSZOnCgefvjhahdDH3/8sejQoYPQ6XSia9eubhc0QgixePFij++b63NPnDhRREdH1zonVYN8CxcurHFOtFqtaNu2rVi8eHG1ORk2bJjIyMhQ3tt77rnHbU569+4tIiMjRVlZmds4mtucJCUliezs7GrPL8/HHXfc4TYntR0jVb9atmzpdoy8/PLLynubkZEhWrVq5XaMvPbaayIuLs5tThpqPkpLS0V8fLz45z//6fa6XI/zqk6ePClGjRol9Hq9aN26tVi6dKnIzMx0C/KZTCZx9913i/j4eBERESHGjBnjFugWQojBgwfX+RkDQNx88801zkufPn3cfnn1ZV7at2/vNi+zZ88WrVq1EhEREaJ169aiZcuWbvPy+OOPi44dO7qNo77z8v3334tx48Ypx2hqaqq48sorxaZNm5Rt5LnbsGFDjfspLi4Wf/vb30RERIRITU0V8+bNE4MHD3YLIjkcDjFjxgyRmpoq9Hq9uOyyy8S+ffuqjdfTe7VhwwblPFL1uK16HpGDSLXNxYcffujxdr1eL/7xj3+IAwcO1PjYnj17KueRDz74QJmT+s5F1fdg+fLlbrdPmjRJGburUJkfWV2fq94E+YSo+/3cv3+/GDt2rEhJSRERERGie/fuyh8mZK7zQ81PbT9DgwcPFhMnTnTbvq5zOQWeL3Mk/7Gztt+lqGH4eiy5YpCv8fg6T1u2bBH9+/cXer1etG3bVjz77LNKMg01DF/myGq1iieffFK5bs7IyBB333232/U5BV5N1w/y3Hj6fX7Dhg2iZ8+eQqfTKTGRcORzkO+rr74SnTt3Fna73e32H374QWi1Wr+yHRrToEGD6vVLRGlpqTAYDLVehDWmQYMGib/+9a8hMSfjx48Xzz77rM+Pa2pz0rVrV5GUlBT0+RDCvzmp73zIFi1aJNq3by8sFku991Vfhw8fFiqVSrRr1y4k5qV///5i2bJlPj0mEPPy/fffi7i4OI9ZdI3pq6++Ep06dRJ6vd7tuA3mecSXOQnUMVJVqMyPEKH3uerPMUNERERE1Nxoqpbv1mXUqFE4cOAA/vjjD2RkZMBsNuPMmTN48skncd1111VrOxxKCgsLcejQIXz99dd+72PDhg0YNmyY0ikxmFxfz9tvvx3UObFYLOjWrRv+/ve/+/S4pjgnBQUFeOihh4J+jPgzJ4GYD9nq1avx3HPP+dRxt6GsXr0ad955J7Kzs4M+L2fPnsXYsWPx17/+1evHBGpeVq9ejcceewzx8fH12k99jRo1Cl988QXS09MxZMiQoJ9HfJmTQB4jVYXK/ACh9bnqzzFDRERERNQcSULUb7XHJUuWYPLkyejZsydWrVrl0yLi1DA4J6GF8xGaOC+hg3NBRERERERUf/UO8hEREREREREREVFwqerehIiIiIiIiIiIiEIZg3xERERERERERERhjkE+IiIiIiIiIiKiMMcgHxERERERERERUZhjkI+IiIiIiIiIiCjMMchHFEYmT56Mbt26wWKxuN2+evVq6HQ67NixI0gjc3fmzBncddddaN26NfR6PdLS0jBixAhs3rw52ENrUFlZWZAkCZIkwWg0IisrC+PHj8f3338f7KFhyJAheOCBB6rdvmTJEsTFxTX6eIiIiIiIiCiwGOQjCiPz589HcXExZs2apdxWUFCAKVOmYMaMGejdu3fAn9Nqtfr8mHHjxiEnJwfvvvsu9u/fj1WrVmHIkCHIz88P+PhCzdNPP42TJ09i3759WLp0KeLi4jB8+HA8++yzwR5a0AghYLPZgj0MIiIiIiKiJo1BPqIQ9emnn6Jbt24wGo1ITEzE8OHDoVarsXjxYrz44ovYunUrAOCBBx5Ay5YtMX36dBw/fhzjx49HXFwcEhIScM011+Do0aPKPn/55RdcfvnlSEpKQmxsLAYPHlwt+0+SJLzxxhu4+uqrERkZWWNw6vXXX0d2djYMBgNSU1Pxf//3fwCcQcdNmzbhn//8J4YOHYrMzEz069cP06dPx9VXX608vqCgALfddhuSk5MRExODYcOG4ddff1XuP3ToEK655hqkpqYiKioKF154IdatW+fVGADAbDZj6tSpSElJgcFgwCWXXIJffvlFuX/jxo2QJAnr169H3759ERERgYEDB2Lfvn01zonFYsG9996L9PR0GAwGZGZmYs6cOW7bREdHIy0tDa1bt8agQYPw1ltvYcaMGZg5c6ayb7vdjsmTJ6NNmzYwGo3o2LEjXnnlFWUfP/zwA7RaLfLy8tz2/cADD+DSSy/1ODYhBJ588kkle7JFixaYOnVqja+lNm+88QbatWsHnU6Hjh074r333lPuO3r0KCRJQm5urnJbQUEBJEnCxo0bAVS+t9988w369OkDvV6P//73v36NhYiIiIiIiLzDIB9RCDp58iT++te/4tZbb8XevXuxceNGjB07FkIIDB06FHfffTcmTpyITz75BB9//DGWLl0KIQRGjBiB6OhobNq0CZs3b0ZUVBSuvPJKpby3uLgYEydOxH//+1/89NNPyM7OxsiRI1FcXOz2/E8++STGjBmDXbt24dZbb602vm3btmHq1Kl4+umnsW/fPqxZswaDBg0CAERFRSEqKgorV66E2Wyu8TVed911OH36NL755hts374dvXv3xmWXXYZz584BAEpKSjBy5EisX78eOTk5uPLKKzF69Gj8/vvvdY4BAB5++GF89tlnePfdd7Fjxw60b98eI0aMUPYve/zxx/Hiiy9i27Zt0Gg0Hl+v7NVXX8WqVavw8ccfY9++fVi2bBmysrJqmUmn+++/H0IIfPHFFwAAh8OBVq1a4ZNPPsGePXswc+ZMPPbYY/j4448BAIMGDULbtm3dgmtWqxXLli2rcXyfffYZ5s+fj3//+984cOAAVq5ciW7dutU5tqpWrFiB+++/H//4xz+we/du3HHHHbjllluwYcMGn/f16KOPYu7cudi7dy+6d+/u8+OJiIiIiIjIB4KIQs727dsFAHH06FGP95eVlYmOHTsKlUol5s+fL4QQ4r333hMdO3YUDodD2c5sNguj0Si+/fZbj/ux2+0iOjpafPnll8ptAMQDDzxQ6/g+++wzERMTI4qKijze/+mnn4r4+HhhMBjEwIEDxfTp08Wvv/6q3L9p0yYRExMjysvL3R7Xrl078e9//7vG5+3atat47bXX6hxDSUmJ0Gq1YtmyZcptFotFtGjRQsybN08IIcSGDRsEALFu3Tplm6+//loAECaTyePz33fffWLYsGFu77GrzMxMZT6qSk1NFXfddVeNr+2ee+4R48aNU77/5z//KTp37qx8/9lnn4moqChRUlLi8fEvvvii6NChg7BYLB7vHzx4sNBqtSIyMtLtS6/Xi9jYWGW7gQMHiilTprg99rrrrhMjR44UQghx5MgRAUDk5OQo958/f14AEBs2bBBCVL63K1eurPH1EhERERERUWAxk48oBPXo0QOXXXYZunXrhuuuuw4LFy7E+fPnlfuNRiMeeughRERE4P777wcA/Prrrzh48CCio6OVbLqEhASUl5fj0KFDAIBTp05hypQpyM7ORmxsLGJiYlBSUqJkx8n69u1b6/guv/xyZGZmom3btpgwYQKWLVuGsrIy5f5x48bhzz//xKpVq3DllVdi48aN6N27N5YsWaKMtaSkBImJicpYo6KicOTIEWWsJSUleOihh9C5c2fExcUhKioKe/fuVcZa2xgOHToEq9WKiy++WBmTVqtFv379sHfvXrfX4pphlp6eDgA4ffq0x9c9adIk5ObmomPHjpg6dSrWrl1b6/vkSggBSZKU7xcsWIA+ffogOTkZUVFReOutt9zmYdKkSTh48CB++uknAM4GGePHj0dkZKTH/V933XUwmUxo27YtpkyZghUrVlRbB++mm25Cbm6u29fTTz/tts3evXvd3jcAuPjii6u9b96o6+eIiIiIiIiI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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "y2020_PEImp = d_vars['vQPEImp'][(d_vars['vQPEImp'].sYear=='y2020')]\n", + "y2025_PEImp = d_vars['vQPEImp'][(d_vars['vQPEImp'].sYear=='y2025')]\n", + "y2030_PEImp = d_vars['vQPEImp'][(d_vars['vQPEImp'].sYear=='y2030')]\n", + "y2035_PEImp = d_vars['vQPEImp'][(d_vars['vQPEImp'].sYear=='y2035')]\n", + "y2040_PEImp = d_vars['vQPEImp'][(d_vars['vQPEImp'].sYear=='y2040')]\n", + "y2045_PEImp = d_vars['vQPEImp'][(d_vars['vQPEImp'].sYear=='y2045')]\n", + "y2050_PEImp = d_vars['vQPEImp'][(d_vars['vQPEImp'].sYear=='y2050')]\n", + "\n", + "# Drop all data that is not related to the primary energy import capacity: sPEHYDRR, sPEHYDRC, sPEMNHY,sPEWINON,sPEWINOF,sPESOLPV,sPESOLTE,sPESOLTH,sPEBIOMEC,sPEBIOMAW,sPEBIOMFW,sPESWAST,sPEBIOETHPI,sPEBIODIEPI,sPEBIOGAS ,sPEHUMANE\n", + "y2020_PEImp = y2020_PEImp[~y2020_PEImp.sPE.str.startswith('sPEHYDRR')][~y2020_PEImp.sPE.str.startswith('sPEHYDRC')][~y2020_PEImp.sPE.str.startswith('sPEMNHY')][~y2020_PEImp.sPE.str.startswith('sPEWINON')][~y2020_PEImp.sPE.str.startswith('sPEWINOF')][~y2020_PEImp.sPE.str.startswith('sPESOLPV')][~y2020_PEImp.sPE.str.startswith('sPESOLTE')][~y2020_PEImp.sPE.str.startswith('sPESOLTH')][~y2020_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2020_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2020_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2020_PEImp.sPE.str.startswith('sPESWAST')][~y2020_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2020_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2020_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2020_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "y2025_PEImp = y2025_PEImp[~y2025_PEImp.sPE.str.startswith('sPEHYDRR')][~y2025_PEImp.sPE.str.startswith('sPEHYDRC')][~y2025_PEImp.sPE.str.startswith('sPEMNHY')][~y2025_PEImp.sPE.str.startswith('sPEWINON')][~y2025_PEImp.sPE.str.startswith('sPEWINOF')][~y2025_PEImp.sPE.str.startswith('sPESOLPV')][~y2025_PEImp.sPE.str.startswith('sPESOLTE')][~y2025_PEImp.sPE.str.startswith('sPESOLTH')][~y2025_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2025_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2025_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2025_PEImp.sPE.str.startswith('sPESWAST')][~y2025_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2025_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2025_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2025_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "y2030_PEImp = y2030_PEImp[~y2030_PEImp.sPE.str.startswith('sPEHYDRR')][~y2030_PEImp.sPE.str.startswith('sPEHYDRC')][~y2030_PEImp.sPE.str.startswith('sPEMNHY')][~y2030_PEImp.sPE.str.startswith('sPEWINON')][~y2030_PEImp.sPE.str.startswith('sPEWINOF')][~y2030_PEImp.sPE.str.startswith('sPESOLPV')][~y2030_PEImp.sPE.str.startswith('sPESOLTE')][~y2030_PEImp.sPE.str.startswith('sPESOLTH')][~y2030_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2030_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2030_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2030_PEImp.sPE.str.startswith('sPESWAST')][~y2030_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2030_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2030_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2030_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "y2035_PEImp = y2035_PEImp[~y2035_PEImp.sPE.str.startswith('sPEHYDRR')][~y2035_PEImp.sPE.str.startswith('sPEHYDRC')][~y2035_PEImp.sPE.str.startswith('sPEMNHY')][~y2035_PEImp.sPE.str.startswith('sPEWINON')][~y2035_PEImp.sPE.str.startswith('sPEWINOF')][~y2035_PEImp.sPE.str.startswith('sPESOLPV')][~y2035_PEImp.sPE.str.startswith('sPESOLTE')][~y2035_PEImp.sPE.str.startswith('sPESOLTH')][~y2035_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2035_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2035_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2035_PEImp.sPE.str.startswith('sPESWAST')][~y2035_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2035_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2035_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2035_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "y2040_PEImp = y2040_PEImp[~y2040_PEImp.sPE.str.startswith('sPEHYDRR')][~y2040_PEImp.sPE.str.startswith('sPEHYDRC')][~y2040_PEImp.sPE.str.startswith('sPEMNHY')][~y2040_PEImp.sPE.str.startswith('sPEWINON')][~y2040_PEImp.sPE.str.startswith('sPEWINOF')][~y2040_PEImp.sPE.str.startswith('sPESOLPV')][~y2040_PEImp.sPE.str.startswith('sPESOLTE')][~y2040_PEImp.sPE.str.startswith('sPESOLTH')][~y2040_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2040_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2040_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2040_PEImp.sPE.str.startswith('sPESWAST')][~y2040_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2040_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2040_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2040_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "y2045_PEImp = y2045_PEImp[~y2045_PEImp.sPE.str.startswith('sPEHYDRR')][~y2045_PEImp.sPE.str.startswith('sPEHYDRC')][~y2045_PEImp.sPE.str.startswith('sPEMNHY')][~y2045_PEImp.sPE.str.startswith('sPEWINON')][~y2045_PEImp.sPE.str.startswith('sPEWINOF')][~y2045_PEImp.sPE.str.startswith('sPESOLPV')][~y2045_PEImp.sPE.str.startswith('sPESOLTE')][~y2045_PEImp.sPE.str.startswith('sPESOLTH')][~y2045_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2045_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2045_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2045_PEImp.sPE.str.startswith('sPESWAST')][~y2045_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2045_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2045_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2045_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "y2050_PEImp = y2050_PEImp[~y2050_PEImp.sPE.str.startswith('sPEHYDRR')][~y2050_PEImp.sPE.str.startswith('sPEHYDRC')][~y2050_PEImp.sPE.str.startswith('sPEMNHY')][~y2050_PEImp.sPE.str.startswith('sPEWINON')][~y2050_PEImp.sPE.str.startswith('sPEWINOF')][~y2050_PEImp.sPE.str.startswith('sPESOLPV')][~y2050_PEImp.sPE.str.startswith('sPESOLTE')][~y2050_PEImp.sPE.str.startswith('sPESOLTH')][~y2050_PEImp.sPE.str.startswith('sPEBIOMEC')][~y2050_PEImp.sPE.str.startswith('sPEBIOMAW')][~y2050_PEImp.sPE.str.startswith('sPEBIOMFW')][~y2050_PEImp.sPE.str.startswith('sPESWAST')][~y2050_PEImp.sPE.str.startswith('sPEBIOETHPI')][~y2050_PEImp.sPE.str.startswith('sPEBIODIEPI')][~y2050_PEImp.sPE.str.startswith('sPEBIOGAS')][~y2050_PEImp.sPE.str.startswith('sPEHUMANE')]\n", + "\n", + "\n", + "# # set index to sPE, sYear, sSeason, sDay, sHour and the values to vQPEImp and unstack the table\n", + "y2020_PEImp = y2020_PEImp.set_index(['sPE', 'sYear', 'sSeason', 'sDay', 'sHour'])\n", + "y2025_PEImp = y2025_PEImp.set_index(['sPE', 'sYear', 'sSeason', 'sDay', 'sHour'])\n", + "y2030_PEImp = y2030_PEImp.set_index(['sPE', 'sYear', 'sSeason', 'sDay', 'sHour'])\n", + "y2035_PEImp = y2035_PEImp.set_index(['sPE', 'sYear', 'sSeason', 'sDay', 'sHour'])\n", + "y2040_PEImp = y2040_PEImp.set_index(['sPE', 'sYear', 'sSeason', 'sDay', 'sHour'])\n", + "y2045_PEImp = y2045_PEImp.set_index(['sPE', 'sYear', 'sSeason', 'sDay', 'sHour'])\n", + "y2050_PEImp = y2050_PEImp.set_index(['sPE', 'sYear', 'sSeason', 'sDay', 'sHour'])\n", + "\n", + "# # Graph 7 SUBPLOTS the results with the index as x-axis and the values of vQPEImp as y-axis.\n", + "# Put the corresponding title to each subplot\n", + "\n", + "fig, axs = plt.subplots(4, 2, figsize=(15, 15))\n", + "fig.suptitle('Primary Energy Import Capacity', fontsize=16)\n", + "y2020_PEImp.unstack('sPE').plot(ax=axs[0, 0], title='2020', legend=True)\n", + "y2025_PEImp.unstack('sPE').plot(ax=axs[0, 1], title='2025', legend=True)\n", + "y2030_PEImp.unstack('sPE').plot(ax=axs[1, 0], title='2030', legend=True)\n", + "y2035_PEImp.unstack('sPE').plot(ax=axs[1, 1], title='2035', legend=True)\n", + "y2040_PEImp.unstack('sPE').plot(ax=axs[2, 0], title='2040', legend=True)\n", + "y2045_PEImp.unstack('sPE').plot(ax=axs[2, 1], title='2045', legend=True)\n", + "y2050_PEImp.unstack('sPE').plot(ax=axs[3, 0], title='2050', legend=True)\n", + "\n", + "# Dont show x axis labels for the first 7 subplots\n", + "for ax in axs.flat:\n", + " ax.label_outer()\n", + "\n", + "# Add a legend for all images\n", + "plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')\n", + "\n", + "\n", + "plt.show()\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_41364\\3144384501.py:77: UserWarning: No artists with labels found to put in legend. Note that artists whose label start with an underscore are ignored when legend() is called with no argument.\n", + " plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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IiIiIiIi8nBM8hEREREREREREXk4JvmIiIiIiIiIiIg8HJN8REREREREREREHo5JPiIiIiIiIiIiIg/HJB8REREREREREZGHY5KPiIiIiIiIiIjIwzHJR0RERERERERE5OGY5CMiIiIiIiIiIvJwTPIRERERERERERF5OCb5iIiIiIiIiIiIPByTfERERERERERERB6OST4iIiIiIiIiIiIPxyQfERERERERERGRh2OSj4iIiIiIiIiIyMMxyUdEREREREREROThmOQjIiIiIiIiIiLycEzyEREREREREREReTgm+YiIiIiIiIiIiDwck3xEREREREREREQejkk+IiIiIiIiIiIiD8ckHxERERERERERkYdjko+IiIiIiIiIiMjDMclHRERERERERETk4ZjkIyIiIiIiIiIi8nBM8hEREREREREREXk4JvmIiIiIiIiIiIg8HJN8REREREREREREHo5JPiIiIiIiIiIiIg/HJB8REREREREREZGHY5KPiIiIiIiIiIjIwzHJR0RERERERERE5OGY5CMiIiIiIiIiIvJwTPIRERERERERERF5OCb5iIiIiIiIiIiIPByTfERERERERERERB6OST4iIiIiIiIiIiIPxyQfERERERERERGRh2OSj4iIiIiIiIiIyMMxyUdEREREREREROThmOQjIiIiIiIiIiLycEzyEREREREREREReTgm+YiIiIiIiIiIiDwck3xEREREREREREQejkk+IiIiIiIiIiIiD8ckHxERERERERERkYdjko+IiIiIiIiIiMjDMclHRERERERERETk4ZjkIyIiIiIiIiIi8nBM8hEREREREREREXk4JvmIiIiIiIiIiIg8HJN8REREREREREREHo5JPiIiIiIiIiIiIg/HJB8REREREREREZGHY5KPiIiIiIiIiIjIwzHJR0RERERERERE5OGY5CMiIiIiIiIiIvJwTPIRERERERERERF5OCb5iIiIiIiIiIiIPByTfERERERERERERB6OST4iIiIiIiIiIiIPxyQfERERERERERGRh2OSj4iIiIiIiIiIyMMxyUdEREREREREROThmOQjIiIiIiIiIiLycEzyEREREREREREReTgm+YiIiIiIiIiIiDwck3xEREREREREREQejkk+IiIiIiIiIiIiD8ckHxERERERERERkYdjko+IiIiIiIiIiMjDMclHRERERERERETk4ZjkIyIiIiIiIiIi8nBM8hEREREREREREXk4JvmIiIiIiIiIiIg8HJN8REREREREREREHo5JPiIiIiIiIiIiIg/HJB8REREREREREZGHY5KPiIiIiIiIiIjIwzHJR0RERERERERE5OGY5CMiIiIiIiIiIvJwTPIRERERERERERF5OCb5iIiIiIiIiIiIPByTfERERERERERERB6OST4iIiIiIiIiIiIPxyQfERERERERERGRh2OSj4iIiIiIiIiIyMMxyUdEREREREREROThmOQjIiIiIiIiIiLycEzyEREREREREREReTgm+YiIiIiIiIiIiDwck3xEREREREREREQejkk+IiIiIiIiIiIiD8ckHxERERERERERkYdjko+IiIiIiIiIiMjDMclHRERERERERETk4ZjkIyIiIiIiIiIi8nBM8hEREREREREREXk4JvmIiIiIiIiIiIg8HJN8REREREREREREHo5JPiIiIiIiIiIiIg/HJB8REREREREREZGHY5KPiIiIiIiIiIjIwzHJR0Qe5cCBA5g0aRKaN28OPz8/1K9fH8OHD8epU6eKbXv8+HH069cP/v7+CA0NxcMPP4z09HS7bU6cOIEXXngBbdq0QUBAAGJiYnD33Xfj4MGDDp//ypUrGD58OIKDgxEYGIhBgwbh3LlzVfJaiYiIiG4l7ozzZs+eDUEQit18fHyq7PUSEVU2QRRF0d2DICJy1dChQ7F7924MGzYMrVq1QmpqKj766CPk5ubijz/+QIsWLQAAly9fRtu2bREUFISnn34aubm5WLBgAerXr4/9+/dDpVIBAJ5//nksXboUQ4YMQceOHZGVlYXFixfjwoUL2LhxI5KSkuTnzs3Nxe23346srCw899xz8Pb2xnvvvQdRFHHkyBGEhYW55ZwQERER1QbujPNmz56NV199FYsWLYK/v798v1KpxMiRI6v3RBARlROTfETkUfbs2YP27dvLwRsAnD59Gi1btsTQoUOxcuVKAMDEiRPxxRdf4MSJE6hfvz4AYPPmzbjrrruwePFiTJgwAQBw6NAhNG3a1C6Yu3HjBhITE9GkSRPs2rVLvn/+/PmYPn069u/fjw4dOgCwXCFu0aIFXnjhBbz++utV/vqJiIiIait3xnlSki89PR3h4eHV8XKJiCodk3xEVCu0a9cOgCWYA4CoqCj07NkTa9eutduuadOmqFevHjZv3lzi8YYMGYLt27fjxo0b8n0dO3YEAOzfv99u2759++Ls2bM4c+ZMhV8HEREREdmrjjhPSvKlpaVBrVYjICAAgiBU8ishIqpa7MlHRB5PFEVcu3ZNvup65coVpKWloX379sW27dixIw4fPlzqMVNTU+2u4prNZvz1119Oj3n27Fnk5ORU4FUQERERUVHVEefZatSoEYKCghAQEICHHnoI165dq9gLICKqRkzyEZHH++qrr3DlyhU88MADAICUlBQAQExMTLFtY2JikJGRgYKCAqfH27lzJ/bu3SsfD4C8j7NjAsDVq1cr9DqIiIiIyF51xHkAEBISgkmTJmHx4sVYt24dxo8fjzVr1qB79+7Izs6uxFdERFR1vNw9ACKiijhx4gSeeuopdO7cGY888ggAQKvVAgDUanWx7aUV0rRarcPH09LS8OCDD6Jhw4Z44YUX5PtdPSYRERERVY7qivMAYMqUKXb/lhbrGDVqFD755BPMmDGjUl4TEVFVYiUfEXms1NRU3H333QgKCsK6deugVCoBABqNBgAcXsXV6XR229jKy8vDPffcg5ycHPzwww92TZrLe0wiIiIiKrvqjPOcefDBBxEdHV1qjz8iopqClXxE5JGysrLQv39/ZGZmYufOnYiNjZUfk6ZvSNM5bKWkpCA0NLTY1V29Xo/7778ff/31F3799Ve0aNHC7nFpH2fHBGA3BiIiIiIqn+qO80pSr149ZGRklPOVEBFVL1byEZHH0el0GDhwIE6dOoWffvoJt912m93jderUQUREBA4ePFhs3/3796NNmzZ295nNZowePRpbtmzBqlWr0LNnz2L7KRQKtGzZ0uEx9+3bh0aNGiEgIKBiL4yIiIjoFueOOM8ZURRx4cIFRERElOu1EBFVNyb5iMijmEwmPPDAA9i7dy+++eYbdO7c2eF2Q4YMwU8//YRLly7J923ZsgWnTp3CsGHD7LadPHky1qxZg08++QT333+/0+ceOnQoDhw4YBdUnjx5Elu3bi12TCIiIiIqG3fGeenp6cXuW7RoEdLT09GvX79yviIiouoliKIounsQRESumjp1KhYuXIiBAwdi+PDhxR5/6KGHAACXLl1C27ZtERwcjClTpiA3Nxdvv/026tatiwMHDsjTON5//30888wz6Ny5MyZOnFjseIMHD4afnx8AICcnB23btkVOTg6ef/55eHt7491334XJZMKRI0d4lZeIiIioAtwZ5/n6+uKBBx5Ay5Yt4ePjg127dmH16tVo3bo1du/eDV9f3yp85URElYNJPiLyKL169cKOHTucPm77lXbs2DE8++yz2LVrF1QqFe6++2688847iIqKkrcZM2YMVqxY4fR458+fR1xcnPzvy5cv45lnnsFvv/0Gs9mMXr164b333kNCQkLFXhgRERHRLc6dcd5jjz2GPXv24NKlS9DpdGjQoAGGDBmC//73v2zJQkQeg0k+IiIiIiIiIiIiD8eefERERERERERERB6OST4iIiIiIiIiIiIPxyQfERERERERERGRh2OSj4iIiIiIiIiIyMMxyUdEREREREREROThmOQjIiIiIiIiIiLycF7uHkBVM5vNuHr1KgICAiAIgruHQ0RERB5AFEXk5OQgNjYWCgWvidZUjPOIiIiorGpznFfrk3xXr15FvXr13D0MIiIi8kCXLl1C3bp13T0McoJxHhEREZVXbYzzan2SLyAgAIDlzQsMDHTzaIiIiMgTZGdno169enIcQTUT4zwiIiIqq9oc59X6JJ80dSMwMJDBHxEREZUJp4DWbIzziIiIqLxqY5xXuyYfExERERERERER3YKY5CMiIiIiIiIiIvJwTPIRERERERERERF5uFrfk4+IqKYym83Q6/XuHgbRLcnb2xtKpdLdwyAiolrMZDLBYDC4exhEt5xbOc5jko+IyA30ej3Onz8Ps9ns7qEQ3bKCg4MRHR1dK5suExGR+4iiiNTUVGRmZrp7KES3rFs1zmOSj4iomomiiJSUFCiVStSrVw8KBTsnEFUnURSRn5+PtLQ0AEBMTIybR0RERLWJlOCLjIyEr6/vLZdkIHKnWz3OY5KPiKiaGY1G5OfnIzY2Fr6+vu4eDtEtSaPRAADS0tIQGRl5y07pICKiymUymeQEX1hYmLuHQ3RLupXjPCb5iKhc/r2ajc92nkNmvn1POaVCwNB29dCvRbSbRlbzmUwmAIBKpXLzSIhubVKS3WAw3FLBHxFRac5fz8On288iLUdnd78gCOjfIhrD2tdz08hqPqkHHy/kErnXrRrnMclHRGVyI7cA7246ha/3J8MsOt5m64k0LHm4PZJui6rewXkYTt0gci/+DBIR2cvRGfDR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X79+akv82WcHejbNmjWLzMxMOnfuzHXXXUdVVRXffvst9913nzpPdnY2X375JWvWrKFPnz7ceuutTJkyJSjM4kiQl5fHo48+GnKaRqOhrKyM66+/nvz8fK666iouvPBC/va3vwXN63S51RHoirJSampq1PPzz3/+k65du9KpUydyc3PJysrirrvuahVFR3V1NZmZmWRnZzNo0CBeffVVbrjhBj5ftpLU9AxqvQMiGo0GTQM/I61Wy+23386//vUvrFYrAwcO5Ndff6Vz585MnTqV7t27c8kll/D777/z3HPPqW3jX331FVlZWdER3igC8OSTTxIfH6++cnNzj/cutTlEMpirJOzu3bBO/buhKiYckrJlYkNJGbU0oeRLipUfMttanQe+lt3a8jKK98o1TmanwMHW7AjSV5U2TKWNE/xCSppQeVWXFGOtrEDUaEjvFGzOX+at2006DTF6n6WCVq9X2zpPhPANa0W5+n9bTTUbv1kaMD1PbdkNrvO2rlgGyCokp72ele+9FTTPL14VX/ehwxkw+jIAtvzwXcA9UUnWzWhwjRWS79C239VW0IYIUGu2zwMCg2iagkJq+rduu737JnrJHXNyCnqTCcnjofJwIR5P6ETT1kLv3r2bXedJksQF55/HB28t5FBhIecNH8ZFg/vwyIw7+Mttf+bpJx5XCabGYK+zqud+2Q8r6JTflczMTPV19tlnY7fW4nY6EYDH//HkSVHn+Q/majWB9b5Sy/bsP4A+g4bQsXMXHvvnvxBEMeLEccW7TyGNhTDCgXB13tJlq0hNz1A/qyG30cw6T8GSJUto165dQGBcFC2DqCffKYi21KoLbXeEt76+XpUZH6k6SqvVqjen1oIyWh8yWdfjgY+mQtV+SOwAl78KpgTofrFvHkmCUCSSIMBZ0yCzD7w/CUq2wtyRcN3HkNl8MvJokZccy76yOvaWWjmrY/JRr++EUPJJ4ZV8NpuN2tpajDhkAb1GD9qmk7KaA61WS1JSEqWlpTidTioqKnj44Ye59957mTp1agDxNm3aNKZNmxZ2XUOHDuW///0vkiRRuXs946fcxvz5C7jq6gmYzWYc3uLj0KFDmEwmzGZzSH+4+fPnM3/+fAA1pAFQvWEANVUtEgwbNow1a9aEnf79998HvRdq/f4PEXV1dRw+fJjhw4eHXKder+edd94Ju83hw4cj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48vLyxEUFIQNGzZg2bJluHbtGvbv3w+FQoE+ffrg5MmTNdav8nW//vprWFpa8vZ9+OGHdbrf4cOHo7i4GElJSXU6jhBCSMvUlDmvOhMnToSzszMOHjyojVvSa5TzmhblPNJoGCGENENPnjxhXbt2Zba2tuzKlSu81+7evcsAsC+++ELjuHfeeYfZ2tq+8Py///47A8B+++03xhhjSqWSGRkZsVmzZmmUXbJkCQPAioqKalV3qVTK0tLSmFQqrVV5fbFjxw7m4ODAfa1UKlnbtm3Z2rVreeXOnTvHBAIBy8zMZCUlJczOzo6NHj1a43y//vorA8ASExO5fQDY7t27ua/v3bvHALB169YxxhibMmUKGzVqVI319PDwYGvWrNHYHx0dzYRCIbt69Sq3LyUlhfXq1YuJxWLm7OzMoqKimFwu514PDAxkc+fOZZGRkcza2po5Ojqy9evXs5KSEhYeHs7Mzc2Zt7c3279/f411et6FCxfYoEGDmLm5ObOwsGDdu3dnp0+fZowxlpyczACwgoICrvyWLVsYAK7u1d2jWmRkJBs0aFCNdVi5ciUTCATswoULvP1KpZL17NmTdezYkalUKsYYYzExMaxLly7Vnmvjxo3MyspKY//t27cZAHb+/HmN1wIDA1lkZCRv39SpU9k777xTY721qbn+LBJCSEvX1DmvJr169WLdunWrdd2b6+8WynmU86pDOa95oSf5CCHNTllZGUaOHIlr165h79696NixI+/1tm3bwsHBAWfOnNE49tSpUxqPo1dF3bNbWFgIABAKhQgICKjynH/99RfatWsHCwuLetxNxYTSErlEJxurw8pxqamp6NGjB/e1UCjEhAkTsHXrVl65LVu2YMCAAfDw8MCBAweQn59fZW/fyJEj4evrq9E7W5m6J76q1e/qKjIyEowx7NmzB0DFxN0jRoxAr169cPHiRcTHxyMhIQHLli3jHbd582bY29vj1KlTiIiIwKxZszB27Fj0798f586dw7BhwzBp0iRIJJJa1yUsLAyurq44ffo0zp49i0WLFsHQ0LDa8nV9H5ydnXHlyhVcvny52jJbt27F0KFD0aVLF95+oVCI+fPnIy0tDRcvXqzV9bSld+/eSE1NbdJrEkII0S+6yHnVYYwhMzMTDg4Otb+BKs5BOa9qlPMqUM4j2mSg6woQQkhdKJVKvP322zhx4gT27NmDfv36VVluzJgx2Lx5M7Kzs+Hm5gag4tH2a9euYf78+Vy5vLy8KoNbQkICBAIBunfvzu176623sGjRIpw5c4Zb0S0jIwOHDx+u8yPrlUkVUvTZ2qfexzfEXxP/gqmhaa3K3rlzBy4uLrx9YWFhWLVqFbKysuDu7g6VSoXExEQsWbIEAHDt2jUAgL+/f5Xn9PPz48o8TyKRYMmSJRCJRAgMDOT27927F+bm5ryyH3/8MT7++OMa629ra8ubTHrt2rVwc3PDd999B4FAAD8/P9y/fx9RUVGIjo6GUFjRD9alSxfufhYvXoyVK1fC3t4eM2bMAABER0cjPj4ely5dQt++fWusg1pWVhYWLlwIPz8/AED79u2rLZuTk4OvvvoKbdu2RYcOHbj9UVFRXL3UkpKSMHDgQERERCA1NRUBAQHw8PBA3759MWzYMISFhXFzGF27dg2DBw+u8prqz+vatWu1+mPpRfr378+9n2pSqVTj3C4uLsjOzoZKpdIoTwghpOXTZc6rqmx8fDzy8vJ4c8LVFeU8ynmU8ypQzmsa1MhHCGlWPvjgA/z6668YOXIkHj9+jJ9//pn3+jvvvAOgIgzs2LEDgwcPRmRkJEpKSvDll18iICAAU6dO5crHxcXh2LFjCAkJgbu7Ox4/foxdu3bh9OnTiIiIgI+PD1d29uzZ+Ne//oXQ0FB8+OGHMDQ0xOrVq+Hk5IQPPvigad4AHZJKpdyE1mpdu3aFv78/tm7dikWLFuHIkSN4+PAhxo4dyytXU0+yWCzmfT1hwgSIRCJIpVI4ODggISEBnTt35l4fPHgw4uPjecfY2trW6h4YYxAIBACA9PR09OvXj/saAAYMGICSkhLcvXsX7u7uAMC7tkgkgp2dHQICArh9Tk5OAICHDx/Wqg4AsGDBAkyfPh3//ve/ERQUhLFjx8Lb25tXxtXVtaL3XyJBly5dsGvXLt57tXDhQoSHh/OOadu2LQDAzMwM+/btw82bN5GcnIyTJ0/igw8+wDfffIMTJ07A1NSUez+awrZt2zT+AAgLC9MoZ2JiApVKhfLy8hY/xyUhhBBNusx5Hh4eePvttxEQEABjY2P8+eefSExMRNeuXfHee+81zRugQ5TzKOfVF+U8/UKNfISQZkW9etP//vc//O9//9N4XR3+3NzccOTIESxYsACLFi2CWCxGaGgoVq1axVuNLTQ0FDdv3sSGDRuQl5cHY2NjdO7cGRs3buRWcVOzsLBASkoK5s+fj2XLlkGlUmHQoEFYs2ZNg4ZxmBiY4K+Jf9X7+IYwMaj9L1h7e3sUFBRo7A8LC+PC39atWxESEgI7OzsAz3ou09PT0b9/f41j09PTNXr51qxZg6CgIFhZWVX5vpqZmfFCeW3l5+cjLy8PXl5edTru+eEVAoGAt08dHuuyWlhsbCwmTpyIffv2ISkpCTExMUhMTMSbb77JlUlNTYWlpSUcHR2rHApub2//wvfB29sb3t7emD59Oj755BP4+vpi27ZtmDp1Knx9fZGenl7lcer9vr6+tb6nmri5uWnUtapw9/jxY5iZmVHwI4SQVkqXOS8sLAzHjx/Hrl27UFZWBg8PD3z00Uf45JNPuEaT+qCc15W3j3JeBcp5pLFQIx8hpFlJSUmpddmXXnoJv//+e41lhg4diqFDh9b6nK6urtixY0ety9eGQCCo9VAKXerWrZtGjzpQsfLckiVLcPbsWezcuRPr1q3jXgsODoatrS1WrVqlEf5+/fVXXL9+HV9//TVvv7Ozc73C3Yt88803EAqFeOONNwBUDFXYtWsXr9f32LFjsLCwgKurq9av/zxfX1/4+vpi/vz5mDBhAjZu3MgLf15eXrC2ttba9Tw9PWFqaorS0lIAwPjx4/HJJ5/g4sWLvPlaVCoV1qxZg44dO2rM49LYLl++jG7dujXpNQkhhOgPXea8f/3rX7W+dl1Qzvuat59yXgXKeaSxUCMfIYSQWgkODsbixYtRUFAAGxsbbr+npyf69++PadOmQalU4vXXX+deMzMzww8//IDx48dj5syZmDt3LiwtLXHo0CEsXLgQM2bMwIgRI+pUj/LycuTm5vL2GRgYwN7envu6uLgYubm5kMvluH37Nn7++Wf8+OOPWLFiBRcsZ8+eja+//hoRERGYO3cuMjIyEBMTgwULFjTqPCFSqRQLFy7EW2+9BS8vL9y9exenT5/GmDFj6nQe9T1WZmpqCktLS8TGxkIikWDEiBHw8PDAkydP8O2330Iul3N/7MyfPx979uzByJEjsWrVKvTp0wcPHjzA8uXLkZ6ejoMHD/KGuEilUu4JCzULCwuN4ScNkZqaimHDhmntfIQQQgipHcp52kE5r3qU85pIk6/nSwghrVxzXs69d+/ebN26dRr7165dywCwyZMnV3nc0aNHWXBwMLO0tGQAGAD2xRdfaJQDwHbv3l3t9adMmcIdX3nr0KEDV8bDw4PbLxaLmbu7Oxs3bhw7fPiwxvlSUlJYr169mFgsZs7OziwqKorJ5XLu9cDAQBYZGck7xsPDg61Zs6bGent4eLCYmJgq76G8vJyNHz+eubm5MbFYzFxcXNjcuXO574fk5GQGgBUUFFT7PlS+x8rbe++9xxhj7PDhw2zMmDHcNZycnFhISAhLTU3lnae0tJR98sknzMfHhxkaGjJbW1s2ZswY9vfff/PKxcTEVHm9V199lTHG2MaNG5mVlZVGPW/fvs0AsPPnz2u89vx7e/fuXWZoaMiys7OrvW9ta84/i4QQQvRTc/7dQjmPch7lvOZPwFgTzcZICCEEAFBWVobbt2/Dy8tLY4Jjfbdv3z4sXLgQly9frncvaFlZGUaNGoXs7GwcOXKkQfMZ6iOJRAI7OzskJSVh0KBBuq5OsxEVFYWCggKsX7++ya7ZnH8WCSGE6Kfm/LuFct6LUc6rH8p5TYfWLSaEEFJroaGhmDlzJu7du1fvcxgbG2PPnj2YPHkyjh49qsXa6Yfk5GQMGTKEgl8dOTo64vPPP9d1NQghhJBWi3Lei1HOqx/KeU2HnuQjhJAm1lp7lQjRN/SzSAghRNvodwsh+qG1/izSk3yEEEIIIYQQQgghhDRzLX51XZVKhfv378PCwoK3egwhhOhKWVkZSkpKUFRUBJlMpuvqENJq1fSzyBhDcXExXFxcGnUVPtIwlPMIIfqGch4h+qG15rwW38h3//59uLm56boahBBCCGmGsrOz4erqqutqkGpQziOEEEJIfbXEnNfiG/ksLCwAVHx4lpaWOq4NIYQQQpqDoqIiuLm5cTmC6CfKeYQQQgipq5ac8+rVyBcbG4ulS5fy9nXo0AFXr14FUPFY5AcffIDExESUl5cjODgYa9euhZOTE1c+KysLs2bNQnJyMszNzTFlyhSsWLECBgbPqpSSkoIFCxbgypUrcHNzw5IlSxAeHl6nuqqHblhaWlL4I4QQQkid0BBQ/UY5jxBCCCH11RJzXr0HH7/00kvIycnhtj///JN7bf78+fjf//6HHTt24MiRI7h//z5Gjx7Nva5UKhEaGgqZTIbjx49j8+bN2LRpE6Kjo7kyt2/fRmhoKAYPHowLFy5g3rx5mD59On7//ff6VpkQQgghhBBCCCGEkBap3sN1DQwM4OzsrLG/sLAQCQkJ2Lp1K4YMGQIA2LhxI/z9/XHy5En07dsXBw4cQFpaGg4ePAgnJyd07doVn3/+OaKiohAbGwuxWIx169bBy8sLq1atAgD4+/vjzz//xJo1axAcHFzfahNCCCGEEEIIIYQQ0uLU+0m+69evw8XFBe3atUNYWBiysrIAAGfPnoVcLkdQUBBX1s/PD+7u7jhx4gQA4MSJEwgICOAN3w0ODkZRURGuXLnClal8DnUZ9TkIIYQQQgghhBBCCCEV6vUkX58+fbBp0yZ06NABOTk5WLp0KQYOHIjLly8jNzcXYrEY1tbWvGOcnJyQm5sLAMjNzeU18KlfV79WU5mioiJIpVKYmJhUWbfy8nKUl5dzXxcVFdXnFgkhpNGpVCqN5dwJIU3D0NAQIpFI19UghBDSgimVSsjlcl1Xg5BWpzXnvHo18g0fPpz7/86dO6NPnz7w8PDA9u3bq218ayorVqzQWBSEEEL0jUwmw+3bt6FSqXRdFUJaLWtrazg7O7fISZcJIYToDmMMubm5ePLkia6rQkir1VpzXr3n5KvM2toavr6+uHHjBoYOHQqZTIYnT57wnuZ78OABN4efs7MzTp06xTvHgwcPuNfU/1Xvq1zG0tKyxobExYsXY8GCBdzX6qWRCSFEXzDGkJOTA5FIBDc3NwiF9Z45gRBSD4wxSCQSPHz4EADQpk0bHdeIEEJIS6Ju4HN0dISpqWmra2QgRJdae87TSiNfSUkJbt68iUmTJqFHjx4wNDTEoUOHMGbMGABARkYGsrKy0K9fPwBAv379EBcXh4cPH8LR0REA8Mcff8DS0hIdO3bkyuzfv593nT/++IM7R3WMjIxgZGSkjdsihJBGoVAoIJFI4OLiAlNTU11Xh5BWSd1hqM4irXVIByGEEO1SKpVcA5+dnZ2uq0NIq9Sac169Gvk+/PBDjBw5Eh4eHrh//z5iYmIgEokwYcIEWFlZYdq0aViwYAFsbW1haWmJiIgI9OvXD3379gUADBs2DB07dsSkSZPwj3/8A7m5uViyZAnmzJnDNdC9//77+O677/DRRx/h3XffxeHDh7F9+3bs27dPe3dPCKk3mUKFP9Ie4ImUP6ecSCDAED9HOFoa66hm+k+pVAIAxGKxjmtCSOumbmSXy+WtKvwRQsiLKFUMh9IfIK+knLdfAAEGtreHmy11UlZHPQcfdeQSolutNefVq5Hv7t27mDBhAvLz8+Hg4ICXX34ZJ0+ehIODAwBgzZo1EAqFGDNmDMrLyxEcHIy1a9dyx4tEIuzduxezZs1Cv379YGZmhilTpuCzzz7jynh5eWHfvn2YP38+vvnmG7i6uuLHH39EcHBwA2+ZENJQyVcf4vO9abj1qLTK1+3NjfDfOf3hakPhpiY0dIMQ3aKfQUII0fTXrXws/V8a0nKqXsDQ3MgAO2f1g5+zZRPXrHmh3zGE6FZr/RkUMMaYrivRmIqKimBlZYXCwkJYWtIvIkIa4sbDEizbl4aUjDwAgL25GD08bHhl0nOKkfVYAl8nc+x4vz+sTAx1UVW9VlZWhtu3b8PLywvGxvrzxGNpuQICAWAq1spMDoTovZp+Fik/NA/0ORGiPfeeSLF8fzr2XcoBAFgYG6BfOztU/jv5Zl4pbjwsgYuVMXbPGQAnGrmhQV9znlSmgJJVNNIS0hq01pxHP+GEkBeSyBRYfeAaNh3PhELFYCgS4N0BXpg7xAcWxvxGvJxCKd74/hiuPSjB7C1nsTG8N8QGtLCEPitXKJHzpAxFZXIIIEA7BzOYUQAkhBBCWgWZQoW1KTcQn3IT5QoVhAJgfG93fDDUF3bm/LnOn0hkGB1/HLfySjFt82lsm9mPMoOekytVyC0sQ4GkYoodDzsz6oQnpAWjv7wJITW6fK8Qr/3zT/z4520oVAxB/o44MD8Qi0f4azTwAUAbKxMkTOkFU7EIx27k45Pdf6OFPzDcbKlUDA+KynDtQQmKyirmj2FgyHosgVyp0nHtaic8PBwCgQArV67k7f/vf/+r94/oCwQCbrOyssKAAQNw+PBh7nX1vT2/hYSE6LDWhBBCWpJbeSUYHX8MXx+8jnKFCn28bLE3YiCWvxmg0cAHANamYmwK7w07MzEu3yvC//1yHkoV5Tx9pGIMecXluJZbzDXwAcDdAgnKFUod1qz2KOcRUnfUyEcIqRJjDAl/3sbotRW9tc6Wxtg0tRd+nNILXvZmNR7bqa0Vvp/YHUIBsOPsXXyffKOJak1qq7hMjmsPivGgqAyMMZgbGcDH0RxGBiLIlSpkP5Y0m8ZZY2NjfPHFFygoKNB1Veps48aNyMnJwbFjx2Bvb4/XXnsNt27d4l4PCQlBTk4Ob/vll190WGNCdKu8vBxFRUW8jRBSd4wx7DiTjdf++Scu3yuCjakhvpvYDYkz+6KjS81D19ztTPGvKT1hZCDEoasP8dn/rjSbzNBalJYrcONBCXIKpVAyBlOxAbwdzGEqNoBSVdGhq2omnxnlPELqhhr5CCEaHpWUY+qm0/h8bxpkShWGdXRCUuRADOrgWOtzDPZzxNLXXwIAfHXgGn69eL+xqkvqSKZQITNfAplSBUOREB62pvCyN4Op2AAedqYQCgQoKVcgr7j8xSfTA0FBQXB2dsaKFSuqLbNr1y689NJLMDIygqenJ1atWsV73dPTE8uXL8e7774LCwsLuLu7Y/369bwy2dnZGDduHKytrWFra4tRo0YhMzOz2msWFBQgLCwMDg4OMDExQfv27bFx40ZeGWtrazg7O6NTp06Ij4+HVCrFH3/8wb1uZGQEZ2dn3mZjY/P8pQhpNVasWAErKytuc3Nz03WVCGl2isrkiEy8gIU7L0EiU6JfOzskRb6C1zq71PrpqO7uNljzdlcAwOYTd7DpeGbjVZjUiVKlQuajUpQplDAQCuFqYwrvp1OxuNuaQiQUQCpTIrewTNdVrRXKeYTUDTXyEUJ4Mh+VIuTrVKRk5MHIQIjP3+iEHyb1gI2ZuM7nmtTPEzMGegEAvvo9Q9tVJfVUIJGBPe3V9XWygJWpmAv1xoYiuFibAAAeFJWhpEyhy6rWikgkwvLly/HPf/4Td+/e1Xj97NmzGDduHMaPH4+///4bsbGx+PTTT7Fp0yZeuVWrVqFnz544f/48Zs+ejVmzZiEjo+L7Vi6XIzg4GBYWFkhNTcWxY8dgbm6OkJAQyGQyjWsCwKeffoq0tDQkJSUhPT0d8fHxsLe3r/Y+TEwq3vfqzkcIARYvXozCwkJuy87O1nWVCGlW8orL8dq3f+LXi/chEgqwMLgDfp7eB85WdV8gYkRAGywe7gegIufRsF398EQqh5IxGBmI4OtkDluzZzlPbCCEm40pgIpO/UKJ/mcOynmE1A018hFCeDYeu41HJeXwdjDDr3NfxqS+Hg2a82L2IB8AQNZjCSQy/W8waukYY3jyNNDZmYkhEmp+trZmYtiYisEAZBU0j/n53nzzTXTt2hUxMTEar61evRqvvvoqPv30U/j6+iI8PBxz587Fl19+ySs3YsQIzJ49Gz4+PoiKioK9vT2Sk5MBANu2bYNKpcKPP/6IgIAA+Pv7Y+PGjcjKykJKSkqVdcrKykK3bt3Qs2dPeHp6IigoCCNHjqyyrEQiwZIlSyASiRAYGMjt37t3L8zNzXnb8uXL6/kuEdL8GRkZwdLSkrcRQmov8VQWsh5L4GJljB3v98OcwT5VZoHamj6wHcQiIUplStx/ItViTUl9PSmtmGfZxswQBiLNP/ctTQzhYFEx3+LdAmmzmJ+Pch4htUdLIRFCOIwxHEx/CABYNNwfHZwtGnxOGzMxbM3EeFwqw628UnRqa9Xgc5L6k8iUT1fOE8CyhpXVXKxNIJUpUaZQIvuxBF72Zno/wfEXX3yBIUOG4MMPP+TtT09Px6hRo3j7BgwYgK+//hpKpRIikQgA0LlzZ+51gUAAZ2dnPHxY8fNw8eJF3LhxAxYW/J+JsrIy3Lx5s8r6zJo1C2PGjMG5c+cwbNgwvPHGG+jfvz+vzIQJEyASiSCVSuHg4ICEhARePQYPHoz4+HjeMba2trV5OwghhBANB69W/F6LeLU9urs3fFigSCiAl70ZMh4U40ZeCdxsTRt8TlJ/5XIlSmUKCADYmFY/CsfJ0hiS8oqyWfkSeDuaQ0g5j3IeaRGokY8Qwsl4UIx7T6QwMhDiZZ/qHzevK28HMzwuleFmXgk18umYenU1KxPDGnvuRUIB3O1MceNhCUrKFSiTK2Ei1u9fGa+88gqCg4OxePFihIeH1/l4Q0N+o6dAIIBKVfEUY0lJCXr06IEtW7ZoHOfg4FDl+YYPH447d+5g//79+OOPP/Dqq69izpw5+Oqrr7gya9asQVBQEKysrKo8j5mZGXx8fOp8L4QQQsjzHhaX4WL2EwDAq361n2f5RbwdKxr5bj4sweA6zN9MtK9AUvEUn7mxIQyreIpPTSgQwM3WFNcfFkMqV6KkXAFL4+o7f/UB5TxCake//2IjhDSpQ0+f4hvgYw8TsUhr5/V2MMfpzALczCvV2jlJ3alUDIUS9RCOF8+xaGwogrmRAYrK5CguV+h9Ix8ArFy5El27dkWHDh24ff7+/jh27Biv3LFjx+Dr68v17r5I9+7dsW3bNjg6OtZpeKCDgwOmTJmCKVOmYODAgVi4cCEv/Dk7O1O4I4QQ0iSSnz7F19nVCo6WdZ+DrzreDuYAQDlPxxhjXGeujemLG+zEBkJYmRjicakMJWX638gHUM4jpDZoTj5CCOdg+gMAwKv+2u2F9XF8Gv4elmj1vKRuisoqJmIWGwhhVstGXAvjioa94mawAAcABAQEICwsDN9++y2374MPPsChQ4fw+eef49q1a9i8eTO+++47jeEeNQkLC4O9vT1GjRqF1NRU3L59GykpKfi///u/KieBBoDo6Gjs2bMHN27cwJUrV7B37174+/vX6X7Ky8uRm5vL2x49elSncxBCCCEAuClZXvVz0up5Kefph9JyBeRKFURCQa0b7CyMKOcBlPNIy0KNfIQQABUrbF3ghnBoN/w96+Gl8KdLj0vVvbviWs+vZ/60kU9Srmw2q+Z99tln3PALoKJ3dvv27UhMTESnTp0QHR2Nzz77rE5DPUxNTXH06FG4u7tj9OjR8Pf3x7Rp01BWVsb1+KakpEAgECAzMxMAIBaLsXjxYnTu3BmvvPIKRCIREhMT63Qvv/32G9q0acPbXn755TqdgxBCCCmTK/Hn9YrGA2135lLO0w/qobrWJoYQ1nIxFTNjAwggQLlCCVkzWIADoJxHyIsIGGPN46+2eioqKoKVlRUKCwtpBTZCarD9TDY+2nkJndpaYm/EQK2eOytfgle+TIbYQIj0z0IatIpbS1BWVobbt2/Dy8sLxsbaGy5TE5lChau5RQAAP2cLiA1qPxz7am4RZAoVPO3Malyso7XbuHEjli9fjrS0NI15X4h+qulnkfJD80CfEyG1k5zxEFM3nkYbK2McXzREq4tplZYr8FLM7wCA858OrdWUIC2ZLnKeUqVCek4xVIzBx8Ecpka1n2LlxsMSSGQKtLU2gZ25USPWsnmjnNf8tNacR0/yEUIAAIfUQ3W1/BQfALS1MYHYQAiZQoV7BVKtn5+82JOnc7SYGRnUqYEPACyeDvkoLpNrvV4tyf79+7F8+XIKfoQQQvSOOucN8XPUagMfUJEtXKwq/oC+9Yie5tOFQqkCKsZgZCCq87za6qlZSsqbx5BdXaGcR5oL/Z9FnRDS6MrkSqQ+HcIR5K/9Rj6RUIB29ma4mluMG3nFcLcz1fo1SPUqJmJ+uuCGad171y2MDJBfUo7icgUYY1r/46Cl2LFjh66rQAghhGhgjOHw0/n4GiPnAYC3oznuF5bh5sNS9PCwbZRrkOoVqKdkMTOsc06zMDbAgyKgpKyioVBIOa9KlPNIc0FP8hFCcPJWPiQyJRwtjPCSS+M8ruzNTcpMK681NYlMiXKFEkKBAFb1GG5rZmQAgUAAmUIFmUL14gMIIYQQojfScopwv7AMxoZC9PO2a5RrqOflu0Hz8jW5coUSpTIFBABsTOremWtiKIJIKICSMUhlzWNePkJI9aiRjxCCQ+rV1vwdaz1Rb13RpMy6U/B0qK6ViWG95kMUCQXcarzFNJSDEEIIaVbUOe9lHwcYG9ZtKGdtedMKuzqjHq1hbmwIQ4O6/3kvEAhgYaSemoVyHiHNHTXyEdLKMcYadT4+NW8HMwDUyNfUVCqGQm6obv3nEFGvsltC4Y8QQghpVtQ5L0jLq+pWRjlPNxhjeKIeqquFnFdcTvMvE9LcUSMfIa1cek4x7heWwchAiAE+9o12HW4YB/XwNimpXAklYzAQCmFWh5XWnmdh9GxSZlXLXpSdEEIIaTEeFpXh4t1CABWLbjQWn6c5L+uxBOUKGvLZVGRKFWRKFQQCASyN69/Ip158QypTQqGkqVkIac6okY+QVk7du/uyj32dV+OqC3UjX4FEjsdPexxJ4yuTVwRtE7GoQQtmGBuKYCASQsUYJDRklxBCCGkWDl+tGKrbxdUKjpbGjXYdBwsjWBgbQMWAO/mSRrsO4St7OoeesYGwQVPuGIqE3FBuWmWXkOaNGvkIaeUOXlXPx9d4Q3WBikamttYmAGgoR1OSqhv5DBv2z33FfC3qoRwU/gghhJDm4GB60+Q8gUBAozZ0QCqveOrORAtzLaqf5qN5+Qhp3qiRj5BW7GFxGS5mPwFQsehGY6NJmZte2dPwp42Jtin8EUIIIc1HmVyJP2/kAWiinOdAOa+pqUdsGGthNE7lzlxGU7MQ0mxRIx8hrVjK1YrgF9DWCk6NOIRDTT0pM/XwNg3G2LPhulpo5DM3MsCTgsfo+1I7XL95q8HnI0Sb+vbti127dum6GoQQojdO3MxHmVwFFytjdGxj2ejX83akxTeamlSLOc/UyABFTwrwcoA3Mq5TziP6hXJe7VEjHyGt2IW7TwAAL7dvvAU3KuN6eCn8NYlyhQoqxiAUCCA2aPg/9wYiITZ+vxqDh42AnbNrnY49fvw4RowYARsbGxgbGyMgIACrV6+GUsmfnFsgEHCblZUVBgwYgMOHD3Ovh4eH88qot5CQEK6Mp6cnt9/ExASenp4YN24c7zz6LCUlhXdvTk5OGDNmDG7deha4K99j5W3lypUAgMzMTN5+sVgMHx8fLFu2jNc7Hxsbi65du/Ku//jxY8ybNw8eHh4Qi8VwcXHBu+++i6ysLF65yp+FoaEhnJycMHToUGzYsAEqFX/Sbk9PT3z99df1rr+dnR2GDRuG8+fPc+cYNGgQ5s2bx329ZMkSLFq0SOPahBDSWp1/OlpjgI99g+blra1nOa+00a9FAIVSBblSPWKj4TlPKBBg09OcZ9umbZ2OpZxXe5TzKOc1NmrkI6QVy8gtBgD4OVs0yfV8HCn8NSVuCIdhwxbdUJNIJNj1y7/x5vh3UFKHIbu7d+9GYGAgXF1dkZycjKtXryIyMhLLli3D+PHjNYaEbNy4ETk5OTh27Bjs7e3x2muv8YJPSEgIcnJyeNsvv/zCO8dnn32GnJwcZGRk4KeffoK1tTWCgoIQFxfXsDehCWVkZOD+/fvYsWMHrly5gpEjR/LCsvoeK28RERG8cxw8eBA5OTm4fv06li5diri4OGzYsKHaaz5+/Bh9+/bFwYMHsW7dOty4cQOJiYm4ceMGevXqxfscgGefRWZmJpKSkjB48GBERkbitddeg0JR8/dIXer/+++/o6SkBMOHD8eTJ0+qPN/w4cNRXFyMpKSkGq9LCCGtRUZuEQDArwme4gMq57wSGu7ZBNQ5T2wghEjY8D/rJRIJtm/9iXJeE6GcRzmvsVAjHyGtFGMM15428nVookY+dQ9vdoGECyak8Whr0Q21/fv3w8jICJ2790JJuRxKpRKurq6Ij4/nlTt//jyEQiHu3LmD0tJSzJgxA6+//jrWr1+Prl27wtPTE9OnT8fmzZuxc+dObN++nXe8tbU1nJ2d0alTJ8THx0MqleKPP/7gXjcyMoKzszNvs7Gx4Z3DwsICzs7OcHd3xyuvvIL169fj008/RXR0NDIyMrhyR44cQe/evWFkZIQ2bdpg0aJFvNAyaNAgREREYN68ebCxsYGTkxP+9a9/obS0FFOnToWFhQV8fHzqHDguXryIwYMHw8LCApaWlujRowfOnDnDK+Po6Ig2bdrglVdeQXR0NNLS0nDjxg2Ne6y8mZmZ8c5hZ2cHZ2dneHh4ICwsDAMGDMC5c+eqrdcnn3yC+/fv4+DBgxg+fDj3/v3+++8wNDTEnDlzeOXVn0Xbtm3RvXt3fPzxx9izZw+SkpKwadOmGt+DutS/Z8+e+Oqrr/DgwQP89ddfVZ5PJBJhxIgRSExMrPG6hBDSWlx7UDFyooNT0+Q8d1tTGAgFkMiUyCksa5JrtmbqRTeMDRo+VBeoyHnGT3NeqUwJuYJyHuU8ynnNETXyEdJK5RSWobhcAQOhAO3szZvkmvbmYlgaG4Ax4PYjeppPjTEGiUyh9a2gVI4yuRKModoydelpT01NRc8ePSASCKBQMciUwIQJE7B161ZeuS1btmDAgAHw8PDAgQMHkJ+fjw8//FDjfCNHjoSvr69G72xlJiYVKzLLZLJa17M6kZGRYIxhz549AIB79+5hxIgR6NWrFy5evIj4+HgkJCRg2bJlvOM2b94Me3t7nDp1ChEREZg1axbGjh2L/v3749y5cxg2bBgmTZoEiURS67qEhYXB1dUVp0+fxtmzZ7Fo0SIYGhpWW14b78OZM2dw9uxZ9OnTp8rXVSoVEhMTERYWBmdnZ43rz549G7///jseP35c43WGDBmCLl264D//+U+961qV2rwHvXv3RmpqqlavSwghzVGZXInM/Iqs5evcNDnPUCSEh50pAJqapbLGy3kyrtNcWzmvR48eEIuEFfM6K1SU8yjnaaCcp/8MdF0BQohuZDyoeIqvnYOZVuZrqw2BQABvR3Ocz3qCm3kl8G+i4SP6TipXomP07zq5dtpnwTAV1+5XwZ07d+Di4gIjQxEkMgXKFUqEhYVh1apVyMrKgru7OxcglixZAgC4du0aAMDf37/Kc/r5+XFlnieRSLBkyRKIRCIEBgZy+/fu3Qtzc/4fLB9//DE+/vjjGutva2sLR0dHZGZmAgDWrl0LNzc3fPfddxAIBPDz88P9+/cRFRWF6OhoCJ8OfenSpQt3P4sXL8bKlSthb2+PGTNmAACio6MRHx+PS5cuoW/fvjXWQS0rKwsLFy6En58fAKB9+/bVls3JycFXX32Ftm3bokOHDtz+qKgorl5qSUlJGDhwIPd1//79IRQKIZPJIJfLMXPmTEyePLnK6+Tl5eHJkyfVflb+/v5gjOHGjRvo3bt3jffn5+eHS5cu1VimNvVXe/LkCT7//HOYm5vXeG0XFxdkZ2dDpVJxnx8hhLRGNx6WgDHA1kwMB3OjJruut4M5buaV4ubDEgxs79Bk19VnzS3nGRuKIFOqUK5QUc4D5byqUM7Tb9TIR0grpZ6Pz7eJhnCoeTs8beR7SE/yNTdSqRTGxsYwMhBCIqtY2KNr167w9/fH1q1bsWjRIhw5cgQPHz7E2LFjecfW1JMsFot5X0+YMAEikQhSqRQODg5ISEhA586dudcHDx6sMXTE1ta2VvfAGOPmJ0xPT0e/fv148xUOGDAAJSUluHv3Ltzd3QGAd22RSAQ7OzsEBARw+5ycnAAADx8+rFUdAGDBggWYPn06/v3vfyMoKAhjx46Ft7c3r4yrq2tF779Egi5dumDXrl2892rhwoUIDw/nHdO2LX+i7G3btsHf3x9yuRyXL19GREQEbGxsuImPq6KNeZQqv8/VqU391eG1tLQU7dq1w7Zt27j3uyomJiZQqVQoLy/neoQJIaQ1epbzzJtk0Q01b0dzIO0Bzb/cDHE5z1AIlAHlcsp5AOW86s5BOU9/USMfIa0UNx9fEzfyVZ6UmVQwMRQh7bNgrZ6zuEyOO/kSGBmI0N6p+mE6Joa1n8fF3t4eBQUFFeEPFY18QMWQBHX427p1K0JCQmBnZwfgWc9leno6+vfvr3HO9PR0jVW/1qxZg6CgIFhZWcHBQfMpADMzM/j4+NS63mr5+fnIy8uDl5dXnY57fniFepWxyl8DqNNqX7GxsZg4cSL27duHpKQkxMTEIDExEW+++SZXJjU1FZaWlnB0dISFhebPqb29/QvfBzc3N66Mv78/bt68iU8//RSxsbEwNjbmlXVwcIC1tTXS09OrPFd6ejoEAkGt3vv09PQXvs+1qf+2bdvQsWNH2NnZwdra+oXXffz4MczMzCj4EUJaPfWIjSbPeQ6U857XGDlPKlPiZl4JREIB/Jwtqm1wqVfOezrHX7miYigw5TzKeVWVpZynv+gZR0JaKS78NdGiG2reFP40CAQCmIoNtLoJBQIYG4pgbWpYY7m69O5369YNaWlpz8Lf03lgJk6ciMuXL+Ps2bPYuXMnwsLCuGOCg4Nha2uLVatWaZzv119/xfXr1zV6+ZydneHj41Nl8GuIb775BkKhEG+88QaAijB04sQJXo/msWPHYGFhAVdXV61euyq+vr6YP38+Dhw4gNGjR2Pjxo281728vODt7V1l8KsvkUgEhUJR5XwnQqEQ48aNw9atW5Gbm8t7TSqVYu3atdznWZPDhw/j77//xpgxYxpcXzc3N3h7e9cq+AHA5cuX0a1btwZflxBCmjvuSb6mznlPO3NvPKScp9a4OU8MM6Pqs179ch6/M5dyXv1QznsxynmNgxr5CGmFlCqG60/DV9M38lWsqnQzrwQqVcMfFydVU6+4Vpce3BcJDg7GlStXICkuBFAR/hhj8PT0RP/+/TFt2jQolUq8/vrr3DFmZmb44YcfsGfPHsycOROXLl1CZmYmEhISEB4ejhkzZmDEiBF1qkd5eTlyc3N526NHj3hliouLkZubi+zsbBw9ehQzZ87EsmXLEBcXx/Uqzp49G9nZ2YiIiMDVq1exZ88exMTEYMGCBY06z4dUKsXcuXORkpKCO3fu4NixYzh9+nS1c6RUR32PlbeioiJemfz8fOTm5uLu3btISkrCN998g8GDB8PSsur5MJcvXw5nZ2cMHToUSUlJ3PsXHBwMuVyO77//nlde/Vncu3cP586dw/LlyzFq1Ci89tpr1c4JU5f611VqaiqGDRvWoHMQQkhLcE1HT/K1e5rzHhaXo6hM3qTXbk2kTztaGzPnyZUqKFWU8+qKcl7t619XlPNqhxr5CGmFMvNLIVOoYGwohJuNaZNe293WFIYiAcrkKtwvlDbptVuTMllF+DPWYvgLCAhA9+7d8d//7IQAAqgYg1xZ0VAbFhaGixcv4s0339R4hP6tt95CcnIysrKyMHDgQHh5eWH69OlYtGgR1q9fX+d6/Pbbb2jTpg1ve/nll3lloqOj0aZNG/j4+GDSpEkoLCzEoUOHEBUVxZVp27Yt9u/fj1OnTqFLly54//33MW3aNI1JguvD09MTsbGxVb4mEomQn5+PyZMnw9fXF+PGjcPw4cOxdOnSOl1DfY+Vt48++ohXJigoCG3atIGnpydmzpyJESNGYNu2bdWe087ODidPnsTgwYPx3nvvwdvbG+PGjYO3tzdOnz6Ndu3a8cqrPwtPT0+EhIQgOTkZ3377Lfbs2QORqObvvdrUvy7u3buH48ePY+rUqfU+ByGEtASFUjlyCssANP2TfJbGhnC0qFjo4xbNy9do1KvqNkbO+8+unTAQqp/mezZkl3LeM5TzKOfpMwHTxsyLeqyoqAhWVlYoLCystkWbkNYm6e8czNpyDp1drfDr3JdffICWDV19BNcflmDzu70R6Nv6Vl4rKyvD7du34eXlpTFfhjaoVAxX7heBgcHf2RKGWlw9ed++fVi4cCF2HTwBuYqhnb0ZzI0NX3xgJWVlZRg1ahSys7Nx5MgRrQ/X0DWJRAI7OzskJSVh0KBBuq5OqxEVFYWCgoI6/UFR088i5YfmgT4nQjSdznyMsetOwMXKGMcXv9rk15/4r5M4fjMfq8Z2wZgejT8sUt80ds5jjCEtpwhKFUN7R3OY1HL13NpQ57w9h09CqlDB3dYU1qbiFx9YCeU80hgo59UePclHSCukq8mY1bh5+Wi+lkZRplCCgcFAKISBSLsr6oWGhmLmzJkoyMt9eq3aT0KsZmxsjD179mDy5Mk4evSoVuunD5KTkzFkyBAKfk3M0dERn3/+ua6rQQghOqer+fjUaP7lxiVXMihVDAIIuHmStUUj58kp5z2Pcp5uUM6rPVpdl5BW6JqOFt1Q83Y0A64ANyj8NYpnQziEdZpwubbmzZuHnEIp8orLuUmZ68rY2BiLFi3Scs30Q2hoKEJDQ3VdjVbngw8+0HUVCCFEL+hqPj419fzLtPhG41DnPCNDIYTCxsl5ecXlyCmUcsN164pyHtE2ynm1R0/yEdIKXVX38NKTfC1SYyy68bznV9glhBBCiH5QP8mnu85cepKvMTXGohvPe36FXUJI86GVRr6VK1dCIBBg3rx53L6ysjLMmTMHdnZ2MDc3x5gxY/DgwQPecVlZWQgNDYWpqSkcHR2xcOFCKBQKXpmUlBR0794dRkZG8PHxwaZNm7RRZUJarTK5EpmPKiZC1ln4e9rId+sRTcjcGLhFN8QU/gghhJDWhDHGPcmn687cO/kSKFUtevp3nag8YqOxqHOeTKFCC5/Cn5AWp8H/Mpw+fRo//PADOnfuzNs/f/58/O9//8OOHTtw5MgR3L9/H6NHj+ZeVyqVCA0NhUwmw/Hjx7F582Zs2rQJ0dHRXJnbt28jNDQUgwcPxoULFzBv3jxMnz4dv//+e0OrTUirdTOvBCoGWJs+W/2sqTlaVly3oFRGwUHLGGONsuLa89ThT65UUYAnhBBC9ERecTkKJHIIBYDP0yfqmprD03ypUDEUl8l1UoeWrClyntigYsoXFWOQK6lDl5DmpEGNfCUlJQgLC8O//vUv2NjYcPsLCwuRkJCA1atXY8iQIejRowc2btyI48eP4+TJkwCAAwcOIC0tDT///DO6du2K4cOH4/PPP8f3338PmUwGAFi3bh28vLywatUq+Pv7Y+7cuXjrrbewZs2ahlSbkFatcu9uY8zXVhtWJhWrsSpUDKUyGu6pTTKlCkrGIBAIuIa4xmAgEsJAqO7lpc+QEEII0QfqxdU87cwatRGoJoYiIcyejiZ4IqFGPm1Sqhg3iqIxh+tWzpE0aoOQ5qVBfwHOmTMHoaGhCAoK4u0/e/Ys5HI5b7+fnx/c3d1x4sQJAMCJEycQEBAAJycnrkxwcDCKiopw5coVrszz5w4ODubOUZXy8nIUFRXxNkLIM+r5+HQ1GTNQEUrEoop/fp5IZDqrR0ukXgXN2EAIYSM34lL4I4QQQvRLho7nXVazNhUDAJ5IqZFPm9RP8RmKhDAQNe70+uqcV58VdgkhulPvfxkSExNx7tw5rFixQuO13NxciMViWFtb8/Y7OTkhNzeXK1O5gU/9uvq1msoUFRVBKpVWWa8VK1bAysqK29zc3Op1f4S0VNfU4U9H8/EBFb2DVqYVT/MVUvjTKmkTDOFQo0Y+QgghRL9wK+vqMOcBz0ZtUM7TrqYYqqv2bF4+GrFBSHNSr0a+7OxsREZGYsuWLTA2NtZ2nRpk8eLFKCws5Lbs7GxdV4kQvXLtQcVKZ346Dn/W6vBHwzi0Sr3ohkkjLrqhZvR0wmdaYZcQQgjRD7peWVdN3chHIza069nKuo37FB8AGBlUZMky6swlpFmp178OZ8+excOHD9G9e3cYGBjAwMAAR44cwbfffgsDAwM4OTlBJpPhyZMnvOMePHgAZ2dnAICzs7PGarvqr19UxtLSEiYmJlXWzcjICJaWlryNEFKhuEyOe08qnoL1ddST8Ec9vFrV2D28+fn5cHR0RGZmJhf+6Ek+oo/Gjx+PVatW6boahBDSZFQqxnXm6n64Lj3J1xi4aVmaIucZPlthlxB9QzmvevVq5Hv11Vfx999/48KFC9zWs2dPhIWFcf9vaGiIQ4cOccdkZGQgKysL/fr1AwD069cPf//9Nx4+fMiV+eOPP2BpaYmOHTtyZSqfQ11GfQ5CSN2oh3A4Wxpzw2V1hcKf9imUKsiU6vDXOD28cXFxGDVqFDw9PXnDdV+0SvLx48cxYsQI2NjYwNjYGAEBAVi9ejWUSv5TgAKBgNusrKwwYMAAHD58mHs9PDycV0a9hYSEcGU8PT25/SYmJvD09MS4ceN459FnKSkpvHtzcnLCmDFjcOvWLa5M5XusvK1cuRIAkJmZydsvFovh4+ODZcuW8T6r2NhYdO3alXf9x48fY968efDw8IBYLIaLiwveffddZGVl8crV9Fk8fw9VbSkpKdi0aZPG1B5qAoEA//3vf3lfv+h744033uC+XrJkCeLi4lBYWFjHT4AQQpqnuwVSSOVKiA2E8LQz1WlduJxHIza0hjHW6J25VeU8uVIFparmhj7KebVHOa8C5bzGU6+/Ai0sLNCpUyfeZmZmBjs7O3Tq1AlWVlaYNm0aFixYgOTkZJw9exZTp05Fv3790LdvXwDAsGHD0LFjR0yaNAkXL17E77//jiVLlmDOnDkwMqpYdv3999/HrVu38NFHH+Hq1atYu3Yttm/fjvnz52vvHSCkFcnIfdq7q+MhHABgZfJ0QmYKf1qjfqLOsNLKt9okkUiQkJCAadOmAQDEBkIIBAKoGINcWX0j3+7duxEYGAhXV1ckJyfj6tWriIyMxLJlyzB+/HiNBsKNGzciJycHx44dg729PV577TVe8AkJCUFOTg5v++WXX3jn+Oyzz5CTk4OMjAz89NNPsLa2RlBQEOLi4rT4jjSujIwM3L9/Hzt27MCVK1cwcuRIXlhW32PlLSIigneOgwcPIicnB9evX8fSpUsRFxeHDRs28MqoVAxZjyWQKZR4/Pgx+vbti4MHD2LdunW4ceMGEhMTcePGDfTq1Yv3OQDVfxb9+/fn7Rs3bpxG2f79+9f5PXnR90ZlnTp1gre3N37++ec6X4cQQpoj9cq6Pg7mjb4ow4twOY86c7VGplRBxRiElVa+1abnc55I+Gxxj5pGbVDOq58my3msIueVySnntRaN9q//mjVr8Nprr2HMmDF45ZVX4OzsjP/85z/c6yKRCHv37oVIJEK/fv3wzjvvYPLkyfjss8+4Ml5eXti3bx/++OMPdOnSBatWrcKPP/6I4ODgxqo2IS2a+kk+Xc/HB1QerktztWiL/OlTfOJGCH4AsH//fhgZGXGdNYwxDO3VEdt/SkB5pUmZz58/D6FQiDt37qC0tBQzZszA66+/jvXr16Nr167w9PTE9OnTsXnzZuzcuRPbt2/nXcfa2hrOzs7o1KkT4uPjIZVK8ccff3CvGxkZwdnZmbfZ2NjwzmFhYQFnZ2e4u7vjlVdewfr16/Hpp58iOjoaGRkZXLkjR46gd+/eMDIyQps2bbBo0SIoFAru9UGDBiEiIgLz5s2DjY0NnJyc8K9//QulpaWYOnUqLCws4OPjg6SkpDq9lxcvXsTgwYNhYWEBS0tL9OjRA2fOnOGVcXR0RJs2bfDKK68gOjoaaWlpuHHjhsY9Vt7MzMx457Czs4OzszM8PDwQFhaGAQMG4Ny5c9znV1wmh0ypwhOJDPmlMnzyySe4f/8+Dh48iOHDh3Pv3++//w5DQ0PMmTOHd/7qPguxWMzbZ2JiolFWLBbX6T0DXvy98byRI0ciMTGxztchhJDmSF8W3QAqz8lHjXzaIq/UmSsQCLR+/udznkqlwpAe/hU5r9IKu5TzXkxfcl5puQIyRUXOyysup5zXSmjtL8GUlBR8/fXX3NfGxsb4/vvv8fjxY5SWluI///kPN9eemoeHB/bv3w+JRIK8vDx89dVXMDAw4JUZNGgQzp8/j/Lycty8eRPh4eHaqjIhrY56MmZdz9MCPBvGUUQ9vABjgKy0wZtMWgyBXAIjVVntj3vBMNvKUlNT0aNHD+5roVCI10ePxf7/7uT18G7ZsgUDBgyAh4cHDhw4gPz8fHz44Yca5xs5ciR8fX01emcrU8+/KpM1vDE4MjISjDHs2bMHAHDv3j2MGDECvXr1wsWLFxEfH4+EhAQsW7aMd9zmzZthb2+PU6dOISIiArNmzcLYsWPRv39/nDt3DsOGDcOkSZMgkUhqXZewsDC4urri9OnTOHv2LBYtWgRDw+qH0GvjfThz5gzOnj2LPn36QK5U4VZeKSSyZ42zxVI5EhMTERYWpvH72sTEBLNnz8bvv/+Ox48f17sO2lSb96R37944deoUysvLm6pahBCiM1f1MOfRtCzQfs5jTZfz3hijznnP8gLlvBfTdc5TKFW4ky9BSfmzBs1iqYxyXith8OIihJCWgDHGDePooEfhj3p4AcglwHKXBp/G8elWJx/fB8RmLy4H4M6dO3Bx4ddz7Nvj8ePab3Hr9h3YB/hCpVIhMTERS5YsAQBcu3YNAODv71/lOf38/Lgyz5NIJFiyZAlEIhECAwO5/Xv37oW5uTn/Nj7+GB9//HGN9be1teUmkwaAtWvXws3NDd999x0EAgH8/Pxw//59REVFITo6GsKnQ567dOnC3c/ixYuxcuVK2NvbY8aMGQCA6OhoxMfH49KlS1zv94tkZWVh4cKF8PPzAwC0b9++2rI5OTn46quv0LZtW3To0IHbHxUVxdVLLSkpCQMHDuS+7t+/P4RCIWQyGeRyOWbOnInR4ybg+oMSKFQqCABuKM79nAd48uRJtZ+Vv78/GGO4ceMGevfuDaD+n0VlhYWFGud4keq+N57n4uICmUyG3NxceHh41OkaRD+Vl5fzwnxRUZEOa0OIfrnGraxbt39TG4O1ibqRj0ZsaCvn2T7d6qSBOW/c+IlY//23uJV5B85d/CjnNYOc99b4ibjxsISbp9tAJIQAAjx4SDmvtaBGPkJaiUclMjwulUEgAHwcdR/+aBhH8yOVSmFsbMzb16N7d3i174Cd239B74AYHDlyBA8fPsTYsWN55WpamOP5x/knTJgAkUgEqVQKBwcHJCQkoHPnztzrgwcPRnx8PO8YW9vaxV7GGDfEJT09Hf369eMNeRkwYABKSkpw9+5duLu7AwDv2iKRCHZ2dggICOD2OTk5AQBvIakXWbBgAaZPn45///vfCAoKwtixY+Ht7c0r4+rqCsYYJBIJunTpgl27dvHeq4ULF2o83d62bVve19u2bYO/vz/kcjkuX76MuXMjIDcwwbzFsTA2FMHWTAwDoQCGIiEYGPce1VZDPgs1CwsLbmhJZVUF4hd9bzxP3Qtcl953ot9WrFiBpUuX6roahOgdmUKFm3n6sbIuQDmvOaoq5/Xq0Q1e7TvgPzu2oX8Xynm1pbOcFxEBhYEpIhfHQGwg5HKeifjZAE7KeS0fNfIR0kqo52nxtDODibhxVuSqi2dz8lH4g6FpRU9rA117UIJyhRJedqYwN67l6smGtV99z97eHgUFBbx9RgZChL7xFvbs2oF/fB6DrVu3IiQkBHZ2dgCe/QJPT0+vcgLe9PR0jVW/1qxZg6CgIFhZWcHBwUHjGDMzM/j4+NS63mr5+fnIy8uDl5dXnY57fniFQCDg7VOHR9ULVp6rLDY2FhMnTsS+ffuQlJSEmJgYJCYm4s033+TKpKamwtLSEo6OjrCw0PyDzd7e/oXvg5ubG1fG398ff11MwzdfLMOiT6Lh42DFPcVnZmQAGzt7WFlZIz09vcpzpaenQyAQ8K5Z38+iMqFQWOtzvOh743nqISe1KUuah8WLF2PBggXc10VFRXBzc9NhjQjRD5n5pVCoGMyNDNDW2kTX1YGVKeU8jpZy3q1HpSgtV8DNxgTWprWc70xLOe/XXdvx5efRlPNqSVc57/SldKxZ+TkWLl6C9o6WMFTnPDHlvNZEt8suEUKazLP5+HT/FB8ALpzQnHwABIKKoRQN2JihKWRCYzBDUxiaWtT+2DpM3NytWzekpaXx9hkZCDH8jbG4fjUNp06fwc6dOxEWFsa9HhwcDFtbW6xatUrjfL/++iuuX7+u0Uvp7OwMHx8frf/C/uabbyrml3njDQAVYejEiRO8Hs1jx47BwsICrq6uWr12VXx9fTF//nwcOHAAo0ePxsaNG3mve3l5wdvbu8rgVx8KpQoqCKBQKGBnLIRQ+OyzNxOLIBQKMfz1N7F161bk5ubyjpVKpVi7di33eepKXb83Ll++DFdXV9jb2zdyzUhTMTIygqWlJW8jhPBzXmMsylBX6pxXKJXX6cmhFkkLOQ9iM8gET3OeSdPlPEOREKFvjsWNjHScPHWacl4dNHXOUzEGJavIeTbGAoiEz5p6TI0MIBQKETyScl5rQI18hLQSd/JLAQDtHPSkkY8bxkFztWiDQsWgYgwCgOu107bg4GBcuXKF18trIBLCw8MTXXr2xvTp06BUKvH6669zr5uZmeGHH37Anj17MHPmTFy6dAmZmZlISEhAeHg4ZsyYgREjRtSpHuXl5cjNzeVtjx494pUpLi5Gbm4usrOzcfToUcycORPLli1DXFwc15s4e/ZsZGdnIyIiAlevXsWePXsQExODBQsWcPO0NAapVIq5c+ciJSUFd+7cwbFjx3D69Olq50ipjvoeK2/Pz0+Wn5+P3Nxc3L17F//93z5sSfgBfQa8Ajtba145M6OKB/vnfPQpnJ2dMXToUCQlJXHvX3BwMORyOb7//nvecbX5LHQpNTUVw4YN03U1CCGk0WU+0q+cpx6xIVOoUCav/RNQpGqMMciVFY1VYoOmy3kCgQBeXl7o0rM33psxg3JeLegq5+353z78nLAOvfsPhKMdfzVis6ejuOZ8tIRyXitAjXyEtBLq4RJ2ZnVfzrwxqMNfqUwJuZLCX0PJFc8m1xU2Ug9+QEAAunfvju3bt/P2GxkKEfrGWPx96RLefPNNbn4MtbfeegvJycnIysrCwIED4eXlhenTp2PRokVYv359nevx22+/oU2bNrzt5Zdf5pWJjo5GmzZt4OPjg0mTJqGwsBCHDh1CVFQUV6Zt27bYv38/Tp06hS5duuD999/HtGnTNCY5rg9PT0/ExsZW+ZpIJEJ+fj4mT54MX19fjBs3DsOHD6/zPGPqe6y8ffTRR7wyQUFBaNOmDTw9PfF/c2Zh4JChWL/x3xrnMjIQwkAohKW1DQ4d+RODBw/Ge++9B29vb4wbNw7e3t44ffo02rVrxzuuNp+FrpSVleG///0vN3E2IYS0ZPqW88zEIhg8fWL8CS2+0WBypQoMFfPNGQibOOcZPM15f1POU9PHnDd39vsYOGQo4jf8pPE0r4FICGNDEaxtbHEgOZVyXgsnYC38+emioiJYWVmhsLCQhnSQVm3KhlM4ci0PX77VGWN76n7+IqWKwfvj/QCAM0uCYG9upOMaNZ2ysjLcvn0bXl5eGhMc19cTiQxZjyUwExvAuxEXVtm3bx8WLlyIy5cvc72gdwskeFwqg6OFMZytXnw/ZWVlGDVqFLKzs3HkyJEWN4+GRCKBnZ0dkpKSMGjQIF1Xh3PtQTHK5Ep42JrCqoq5fO7kl6JQKoezlTEcLbTzfalL8fHx2L17Nw4cOFBtmZp+Fik/NA/0ORFS4YPtF7Hr3F18FNIBswc1bA4tbem57A88KpHht3kD4efcen4+GyPnlZQpcOtRCYwMhOjQiO9lVTkvt7AMD4vLYGsmhqvNi+f4o5ynG7fySlBSrkBbaxPYVfF31b0CCfJLZbA3N4KLHszb2VCU86pHT/IR0koUPu3hVT9Bp2sioQCWxhVDBGnltYaTPX0asrGGcKiFhoZi5syZuHfvHrfPyKBiCEC5QlmrcxgbG2PPnj2YPHkyjh492ij11KXk5GQMGTJEr4KfXKlCmbzi81EPzX2eqbhif2l57T5HfWdoaIh//vOfuq4GIYQ0CXXOszbRjyf5AMCSVtjVGnXOa6wpWdSqzHmGFdcsV9Ru5A3lvKanUjGUymrOeer9peWKJqtXY6KcVz1aXZeQVoILf7VdjasJWJkaoqhMgUIaxtFg6uG6jR3+AGDevHm8r40M6hb+gIoAuGjRIm1WS2+EhoYiNDRU19XgUQc6E0MRt6Lu88yMKhprJeUKMMb0YuL2hpg+fbquq0AIIU1GnaX0pTMXqDz/MjXyNZS8iTpzgRpyXh3mVqSc17QksorsZigScp/X89SduWVyJZQqFW9hjuaIcl71mvcnSwipNfUCF9am+hT+nq28RhpGxk3G3PQNM+oeXplCRSvo6amSp4181fXuAhUNgCKBAErGuKf+CCGENA/qhjS9ynlPO5aLKOc1mKwJO3Ofpx6xoVCpoKB5tPVSSfmzp/iq66QVGwghNhCCAZDIKOe1ZNTIR0groFKxSsM49Cn8UQ+vtjTlk3zPE4uEEAgEUDFGi6joKXUjn3kNjXwCgQCm6qEcFP4IIaRZ0bdpWYBndaGFNxquKZ/ke55IKODyZV1GbZCmU5ucBwBm4pY1ZJdUjRr5CGkFSmQKqJ4+YGWpR+GP5mrRDsbYszn5dNDIJxAIuOvKKPzpHZlCCZlCBQEE3JDc6piJK16n8EcIIc0HY4xbXVcvG/ko5zWYLnMe8KxxkTpz9Y9SxSB92jlr/qKcZ9Sy5l8mVaNGPkJagcKn4crYsGL5dH2hfqqQhus2jFLFoHo6TNZQBz28AGAoqhgaIFfScF19ox7CYSIWvXD+lcrhj4ZeE0JI81AmV3GdbPo1XJdynjYwxiBXPM15OmrkU1+XGvn0T6lMAQb2dDhu7TpzJXIlVCrKeS0VNfIR0gro44prAIU/bam84ppQR4slUPjTX6XcEI4XN/CbGIogEAigUKloSA4hhDQT6hwlEgpeOFyvKT0brks5ryHkSgYGBgEEXKdqU6POXP3F5Tzxi3/2xQZCGIiEYIxBQvMvt1jUyEdIK6AeJqFPQziAysM4aK6WhtDlfHxqXPijXkG9whir9TwtACAUCmCq7uWV0ZBdQghpDp5UWllXn1ZG5zpzabhug6g7UA0NBDr7fKkzV3+VlD3NecYvznkCgeDZ03w0NUuLRY18hLQCXPjToyEcwLMnC6mHt2G4lXV12Mhn8PTatOqafpEpVJArVRWLatSihxeoPCkz9fASQkhzwK2sq2educ9yHnXmNoSu5+MDAEMhPcmnjxRKFaTyZyvr1oa6XAk18rVY1MhHSCugjyvrAs8aHWm4bsNU7uFtbPn5+XB0dERmZiZv/7MeXgp/+kQd4EzFIgiFtfv+UC/OoY+Lb4wfPx6rVq3SdTUIIUSvcCvr6llnriXNvawVTTlio7qcR525+qn06YIbRgaiWn9/qDtzJTL9m3+Zcp52UCMfIa2Avg7X5RbeoGEcDaKebLspenjj4uIwatQoeHp68vY/m6ul6vB3/PhxjBgxAjY2NjA2NkZAQABWr14NpZL/tJhAIOA2KysrDBgwAIcPH+ZeDw8P55VRbyEhIVwZT09Pbr+JiQk8PT0xbtw43nn0WUpKCu/enJycMGbMGNy6dYsrU/keK28rV64EAGRmZkIgEMDewhhd3Gzg39YWPj4+WLZsGS/QxcbGomvXrrzrl5UU4R+xizGk10sQi8VwcXHBu+++i6ysLI265ubmIjIyEj4+PjA2NoaTkxMGDBiA+Ph4SCQSjfIrVqyASCTCl19+qfGaUqnEypUr4efnBxMTE9ja2qJPnz748ccfuTJLlixBXFwcCgsL6/y+EkJIS1Wor0/ymdLqutrAPcnXBIurVZ/znnbmqliVDUOU82pPmznP2lSMLm42CHC3q3XOkxQ/wZexizGsTycYGRlRzmuBqJGPkFaAe5JPz3p41T3ONFy3YZoq/EkkEiQkJGDatGkarxlyPbya4W/37t0IDAyEq6srkpOTcfXqVURGRmLZsmUYP368RvmNGzciJycHx44dg729PV577TVe8AkJCUFOTg5v++WXX3jn+Oyzz5CTk4OMjAz89NNPsLa2RlBQEOLi4rT1djS6jIwM3L9/Hzt27MCVK1cwcuRIXlhW32PlLSIigneOhMQ9OHT2Ki5eTsfSpUsRFxeHDRs2VHvNx48fY0D/fjj15xEsWbEaZ/9OQ2JiIm7cuIFevXrxPodbt26hW7duOHDgAJYvX47z58/jxIkT+Oijj7B3714cPHhQ4/wbNmzARx99VGUdli5dijVr1uDzzz9HWloakpOTMXPmTDx58oQr06lTJ3h7e+Pnn3+uy1tJCCEtWuU5+fSJutGxuEwBJc3ZW2+yJnqSr6acZ/C0M5cxBoWKcp42aCPnbdr+Kw6dvYqzf1+pdc7r168fTh2ryHl/XbhCOa8lYi1cYWEhA8AKCwt1XRVCdGbhjgvMI2ov++7wdV1XhSfniZR5RO1l7RbvYyqVStfVaTJSqZSlpaUxqVTa4HOpVCp2+e4TdjG7gEllCi3Urno7duxgDg4O3NdKpZK1bduWrV27lqlUKnYpu6Ief50+wwQCAcvMzGQlJSXMzs6OjR49WuN8v/76KwPAEhMTuX0A2O7du7mv7927xwCwdevWMcYYmzJlChs1alSN9fTw8GBr1qzR2B8dHc2EQiG7evUqty8lJYX16tWLicVi5uzszKKiophcLudeDwwMZHPnzmWRkZHM2tqaOTo6svXr17OSkhIWHh7OzM3Nmbe3N9u/f/+L3j6eCxcusEGDBjFzc3NmYWHBunfvzk6fPs0YYyw5OZkBYAUFBVz5LVu2MABc3au7R7Xbt28zAGzbb0fZ33efMOXTn69XX32VzZ49mysXExPDunTpwn39/vvvMzMzM3b+6i12MbuA3SuQMMYYk0gkrG3btiwkJIQrGxwczFxdXVlJSUmVdXj+ZzolJYW1bduWyWQy5uLiwo4dO8Z7vUuXLiw2Nrbae1JbunQpe/nll19YrjZq+lmk/NA80OdECGNfJKUzj6i9LGbPZV1XhUeuUDKPqL3MI2ove1xSruvqNBlt5jzGGLuaU8QuZhewYqn8xYUboKacxxhjV+4VsovZBez4X6co571AU+a8i9kFTK5QMsZqn/P+vnabXcwuYHfySxljlPNaGnqSj5BWQP0kn6W+9fA+fZJPqWKtevJXxhgkckm9thJZKUoVEpQppVCoyup8PKvDXBypqano0aMH97VQKMSECROwdetWCAQCrpd3y5YtGDBgADw8PHDgwAHk5+fjww8/1DjfyJEj4evrq9E7W5mJiQkAQCZr+KTdkZGRYIxhz549AIB79+5hxIgR6NWrFy5evIj4+HgkJCRg2bJlvOM2b94Me3t7nDp1ChEREZg1axbGjh2L/v3749y5cxg2bBgmTZpU5bCF6oSFhcHV1RWnT5/G2bNnsWjRIhgaVv/z2ZD3wczIAEKBAGfOnMHZs2fRp0+fKsupVCokJiZW1M3FBcCz4dcmJiaYPXs2fv/9dzx+/Bj5+fk4cOAA5syZAzMzsyrP9/wKgAkJCZgwYQIMDQ0xYcIEJCQk8F53dnbG4cOHkZeXV+P99O7dG6dOnUJ5eXmt7p8QQlo6bk4+Pct5BiIht7J7ax610ZCcVyorRZGsFGVKKZTQXc4Dnk3NsnXrL5TzXqApc56JoQgGImHdcl7bpzlPQTmvJardEiyEkGZNX1ddMzYUQWwghEyhwhOJHBbG+lW/piJVSNFna9W/kBvbXxP/gqmhaa3K3rlzBy5PG3/UwsLCsGrVKmRlZcHQ2AblchV2bt+OTz9dAgC4du0aAMDf37/Kc/r5+XFlnieRSLBkyRKIRCIEBgZy+/fu3Qtzc3Ne2Y8//hgff/xxjfW3tbXlTSa9du1auLm54bvvvoNAIICfnx/u37+PqKgoREdHQyis6Afr0qULliypuJ/Fixdj5cqVsLe3x4wZMwAA0dHRiI+Px6VLl9C3b98a66CWlZWFhQsXws/PDwDQvn37asvm5OTgq6++Qtu2bdGhQwduf1RUFFcvtaSkJAwcOJD7esobwRCKhJDLZJDL5Zg5cyYmT55c5XXy8vLw5MkT+Pv7w9BAcyEVf39/MMZw48YNMFYxLLtyfQDA3t4eZWVlAIA5c+bgiy++AAAUFRVh586dOHHiBADgnXfewcCBA/HNN99wn+Xq1avx1ltvwdnZGS+99BL69++PUaNGYfjw4bxruLi4QCaTITc3Fx4eHtW+b4QQ0lo80dNGPqCiTiXlCjyRyABU3VjQ0rWYnGdqh9JyOXbt2I5oynk10vucxy2Y92wubcp5LQc9yUdIK6Cvc/IBlRbfaMU9vM2FVCqFsbExb1/Xrl3h7++PrVu3wkAoxJmTx5CX9xBjx47llaupJ1ksFvO+njBhAszNzWFhYYFdu3YhISEBnTt35l4fPHgwLly4wNvef//9Wt0DY4zreUxPT0e/fv14PZEDBgxASUkJ7t69y+2rfG2RSAQ7OzsEBARw+5ycnAAADx8+rFUdAGDBggWYPn06goKCsHLlSty8eVOjjKurK8zMzODi4oLS0lLs2rWL914tXLhQ433o2bMn7xxfrE3AiVNncPHiRWzfvh179uzBokWLaqwbY+yFC6lU59SpU7hw4QJeeuklXg/sL7/8Am9vb3Tp0gVAxfeNh4cHtm3bxpXp2LEjLl++jJMnT+Ldd9/Fw4cPMXLkSEyfPp13DXVvd1161AkhpCXjFt7Qx5xnSjmvuXhRzjMUCXDm5DE8opz3Qk2Z8/48eaoeOe9ZZ25dnvaknNc80JN8hLQC+jqMA6gIfw+Ly1t1+DMxMMFfE/+q17H5JTLkFElhZWwIN9va9dQ+f+3asre3R0FBgcb+sLAwbN26FZPej0TSf3di8KtDYWdnB+BZz2V6ejr69++vcWx6errGql9r1qxBUFAQrKys4ODgoHGMmZkZfHx8al1vtfz8fOTl5cHLy6tOxz0/vEIgEPD2qcOjSlX7BrHY2FhMnDgR+/btQ1JSEmJiYpCYmIg333yTK5OamgpLS0s4OjrCwsJC4xz29vbVvg/qxrk2Lq54ya8DREIB/P39cfPmTXz66aeIjY3VCPIODg6wtrZGeno6r4dXxRiEAgHS09MhEAjg4+PDheiMjAzeOdq1awfgWUBTS0hIwJUrV2Bg8Cx2qFQqbNiwgTfBt1AoRK9evdCrVy/MmzcPP//8MyZNmoRPPvmE+9weP37M1ZcQQoh+d+ZaUWdug3JeoVSO7AIJzMQG8LKv+5OQ2sx5U2fPQ9J/dyKQct4LNXbOUz1d/MT5ac4TG4jqmPMEEEAABgaFksHQgHJeS0JP8hHSCjwbrit+Qcmmpw5/6jq2RgKBAKaGpvXaRAIjGItMYGlsVq/jn59PoybdunVDWlqaxv6JEyfi8uXLSLt4Hn/s34PX33qbey04OBi2trZYtWqVxnG//vorrl+/jvDwcN5+Z2dn+Pj4aP2X+zfffAOhUIg33ngDQMWwhBMnTvB6MI8dOwYLCwu4urpq9dpV8fX1xfz583HgwAGMHj0aGzdu5L3u5eUFb2/vKoPfi5TJK1ZnExsIIRI++4xFIhEUCkWVc74IhUKMGzcOW7duxaOHD7jvDYVSBalUirVr13Kfp52dHYYOHYrvvvsOpaWlNdbl77//xpkzZ5CSksLrjU5JScGJEydw9erVao/t2LEjAPCucfnyZbi6usLe3r72bwghhLRg+rq6LvCs4ZFyXgNznpHuc96VSxcqct7ocdxrlPOq15g5r1xRkfNEAgFv1eXa5rwHDx5wozZklPNaHGrkI6SFK1coIX36B7+VXvbwVjQ8tuYe3oaQPZ0wt/Iv+MYSHByMK1euaPTyenp6on///lgQMQsqpQqDhz6bW8PMzAw//PAD9uzZg5kzZ+LSpUvIzMxEQkICwsPDMWPGDIwYMaJO9SgvL0dubi5ve/ToEa9McXExcnNzkZ2djaNHj2LmzJlYtmwZ4uLiuF7R2bNnIzs7GxEREbh69Sr27NmDmJgYLFiwgJunpTFIpVLMnTsXKSkpuHPnDo4dO4bTp09XO59NddT3WHkrKioCAJTJK74vJEVPkJubi7t37yIpKQnffPMNBg8eDEtLyyrPuXz5cjg7O2PYsGE4mXIQuffv4nDKUQQHB0Mul+P777/nyq5duxYKhQI9e/bEtm3bkJ6ejoyMDPz888+4evUqRCIRgIre3d69e+OVV15Bp06duO2VV15Br169uImZ33rrLaxZswZ//fUX7ty5g5SUFMyZMwe+vr7cnDZARc/3sGHD6vReEUJIS6ZuQLPSy85cynkNoU85b96c96BSqhBIOa9GTZPzKv62k5Y8wYMHD+qc84YOHYrjT3NeypEjlPNamiZcyVcnWvLSyITUxoMiKfOI2ss8F+1lSqXqxQc0sQ+2X2AeUXvZ98nXdV2VJlPTcu51dS23iF3MLmCFEpkWavZivXv3ZuvWrdPYv3btWgaAjXxrPLuaU6Tx+tGjR1lwcDCztLRkABgA9sUXX2iUA8B2795d7fWnTJnCHV9569ChA1fGw8OD2y8Wi5m7uzsbN24cO3z4sMb5UlJSWK9evZhYLGbOzs4sKiqKyeVy7vXAwEAWGRnJO8bDw4OtWbOmxnp7eHiwmJiYKu+hvLycjR8/nrm5uTGxWMxcXFzY3Llzue+H5ORkBoAVFBRU+z5UvsfK23vvvccYYyz17BXefpFIxFxdXdmMGTPYw4cPufPExMSwLl268M6dl5fHIiIiWJu2rszA0JA5Ojqx8PBwdufOHY163L9/n82dO5d5eXkxQ0NDZm5uznr37s2+/PJLVlpaysrLy5mdnR37xz/+UeV9fPHFF8zR0ZHJZDK2fv16NnjwYObg4MB9buHh4SwzM5MrL5VKmZWVFTtx4kS1701d1PSzSPmheaDPibR2CqWKeUTtZR5Re1lecZmuq6Nhxf505hG1ly399Yquq9JktJnzbuWVsIvZBSy/pGk+29rkvMv3nmi8TjnvmabIecfPpzU457k8zXkOlPO0ci19ImCsDjMtNkNFRUWwsrJCYWFhtS3ahLRk1x8UY+iao7A2NcSFaP3rFfl8bxoS/ryN915ph8Uj6tbD1VyVlZXh9u3b8PLy0pgvo66u3C+EUsXg62QBY0ORlmpYvX379mHhwoW4fPmyRi9omVyJaw+KIRII8FJbq2rPUVZWhlGjRiE7OxtHjhxpcXNuSCQS2NnZISkpCYMGDdJJHdJziiBXquDtYA4zo/pNv5v9WIICiQzOlsZwtGzY96m2xMfHY/fu3Thw4IBWzlfTzyLlh+aBPifS2hWUytDt8z8AANfjhjfJE191se7ITaxMuorR3dti9biuuq5Ok9BmzsvILUa5Qol29mYwN278ETk15TyFUoW0nIonyTq5WEEorHooMOW8xnf9QTGkciU87Ezr/QRvTqEUecXlsDc3got17edubEyU87RDv34LkGanoFSGf/x2Fe/9+wzyistffABpck/UkzHr4TwtwLN6tea5WupLqVJB+XTi3aYK9aGhoZg5cybu3bun8Zp6bg8lY1y9qmJsbIw9e/Zg8uTJOHr0aKPVVVeSk5MxZMgQnQU/uVIFuVIFAdCghl9Dg4rvKVkdV9htTIaGhvjnP/+p62oQ0mqUlCvw3eHreHfTaWTl00qH+kid88zEIr1r4AOe5bxCynl1xhjjFtJS/05ubDXlPJFQAOHTOf7kNSxCQTmvcalUjJuWxaQBOU/89N8L9ZBwfUA5TztodV1SL4VSORL+vI0Nf95GSbkCAOBoYYzP3+ik45qR56lDlZWp/s3TAjybkJnmaqk7mbKiIU0kFPAWV2hs8+bNq3K/SCiEUCCAijEolCqIhNUHD2NjYyxatKiRaqhboaGhCA0N1dn1pbKKeVqMDEUN+r4QP220lSv154H/6dOn67oKhLQKEpkCP524gx+O3ETB0xxhZCBE/Ds9dFwz8rxnK+vqZ86j1XXrT6FiULGm7cwFqs95AoEAhiIByhUMciVDTQMFKOc1njKFEgwMBkJhg74v1MfK9agzl3KedlAjH6kTiUyBDX/exvqjt1BUVtG452VvhtuPSrHtTDbmDvGBk54M6yIV1D28+rjiGvCs8VG9MhypPfnTnjexHvXcG4qEKFcoIVeqYNQEw4eJJvVCOw3p3QX0M/wRQhpXuUKJLSezsDblJh6VVIzQ8LAzRdZjCZIu5+Lag2L4OtV9JUjSeJ5I9HdlXeDZom9PqJGvzrin+ERC7gk6XTMQCVGuUEFB2UBn1J25JmJRnVZPfh7lvJZLf/4yJM3CB9sv4qsD11BUpkB7R3PEh3XHoQWB6OlhA5lChX8dvaXrKpLnqMOfvg7XtaLhuvWmHkYpbqIhHLWhHrIrr2G4LmlclcNfQ3DhT4+GcRBCGteyven4bG8aHpWUw83WBF++1RmHFgQi5CVnAMDa5Bs6riF5XqGed+ZaP50vjHJe3TXlyrq1ZShUNwxRztMVLucZNuz7wtCgIrMrVAwqyu0tiv78i0H0XnGZHH+kPQAAfPlWZ/w27xUMD2gDoVCAuUMqlirf8lcW8ktobj598mwYh76Gv4p6FVEPb53J9TH8Ua+gzmn7Sb6KORbp8ySkpVOqGH69eB8A8PEIPxz+YBDG9nSDgUiIOYMrct6vF+/j9qNSXVaTPEfdeKavOU/9JF+RVI4Wvt6j1sn1sTPXQD2VB+UCXeFyXgM7c0UCAURPnwTUp/mXScPpz78YRO+duJkPhYrB084UY3u68eZ6CvR1QGdXK0jlSiT8eVuHtSTP0/seXhrGUW/6+CSfwdMn+RTUw6sT2lp0A6iY69FAqA5/9HkS0tJdvPsEhVI5LI0N8O4AL14HUqe2Vhji5wgVA+JT6Gk+fdJcOnNlShXXOEFqR/27Vz1Hrj4wEFJnri5pa9EN4Okciwb0ebZE+vOXIdF7R67lAaho0HueQCDA3Ke9vD+duEMraOkRdQ+vvjbyqeslkSn1anWn5kCmpCf5CJ+2Ft1QoyG7hLQeRzIqct7A9g4wqOL3inrUxn/O3cPdAlppV1+oc56lnuY8U7GIm8qDhuzWjX6O2KDOXF3S1qIbapTbWyb9+ReD6DXGGNfI90oVjXwAEOTvBD9nC5SUK7DpeGYT1o7U5Imer7pmYWwI9ZyxtPJa3cgV6h5e/fmn3FAPV2RtTbQ1VFeNwh8hrcfR6+qcZ1/l693dbfCyjz0UKoYfjtAczPpCvXCZeu47fSMQCGiF3XrSxxEblAt0S1uLbqhRbm+Z6vUvRnx8PDp37gxLS0tYWlqiX79+SEpK4l4vKyvDnDlzYGdnB3Nzc4wZMwYPHjzgnSMrKwuhoaEwNTWFo6MjFi5cCIVCwSuTkpKC7t27w8jICD4+Pti0aVN9qku04PajUtwtkEIsEqJvO7sqywiFAm7Olg3HbqO4jH6R6wN9H64rEgpgaawOf7TCbm0pVQyKp/OkqedH0QeGNIxDp7S16IYaDeMgpHV4IpHhYvYTANV35gLPnubbdiYbD4rKmqJq5AWK9Hy4LkCLrNUHY0w/F96otMAazbHY9LS16Iaa+kEBGk3VstTru8PV1RUrV67E2bNncebMGQwZMgSjRo3ClStXAADz58/H//73P+zYsQNHjhzB/fv3MXr0aO54pVKJ0NBQyGQyHD9+HJs3b8amTZsQHR3Nlbl9+zZCQ0MxePBgXLhwAfPmzcP06dPx+++/N/CWSX2on+Lr6WkDMyODasuNCGiDdg5mKJTK8fPJrKaqHqlBoXp1XQp/LYq60aVi3rSmC3/5+flwdHREZmZmla+rh3gplBT+dEHbT/Kp5wHS5zn50tLS4OrqitJSWgyAkPr688YjqBjg62SONlYm1Zbr42WLXp42kClUWH+UnubTB/o+LQvwbDQJdebWnlLFoGJNP2KjtjmPMQYlrcja5LS16IZac3gyk3Je3dXrX4yRI0dixIgRaN++PXx9fREXFwdzc3OcPHkShYWFSEhIwOrVqzFkyBD06NEDGzduxPHjx3Hy5EkAwIEDB5CWloaff/4ZXbt2xfDhw/H555/j+++/h0xW8Y//unXr4OXlhVWrVsHf3x9z587FW2+9hTVr1mjv7kmtHa1hPr7KREIB5gyq6OX9MfUW19tAdIcbrqvX4Y+GcdSVXEfz8cXFxWHUqFHw9PSs8nVDkQACAAwMikrh7/jx4xgxYgRsbGxgbGyMgIAArF69Gkol/98IgUDAbVZWVhgwYAAOHz7MvR4eHs4ro95CQkK4Mp6entx+ExMTeHp6Yty4cbzz6LOUlBTevTk5OWHMmDG4devZH9SV77Hytu7bVRAAyL2XzdsvFovh4+ODZcuW8RpfY2Nj0bVrV971Hz9+jHnz5sHDwwNt7SwR1MMfH8x5D1lZ/I4b9Wfx/vvva9zDnDlzIBAIEB4ervHaiRMnIBKJEBoayts/fvx43ucIAL/99hsEAgFiY2N5+2NjY+Hu7g4A6NixI/r27YvVq1dX95YSQl5APR/fi3KeQCDA3CHtAQBb/rqD/JLyRq8bqVlzyHk0XLfu1DnPQCiEUAtz7NbWi3KeUCCotPgG5bz6aEjO+/7rVQCAB1rKeU425gjq4Y+F/zeLcl4L0uC/DpVKJRITE1FaWop+/frh7NmzkMvlCAoK4sr4+fnB3d0dJ06cAFDxwQcEBMDJyYkrExwcjKKiIu5pwBMnTvDOoS6jPkd1ysvLUVRUxNtIw5TJlThxKx9AzUM41F7v6gI3WxPkl8qw/++cxq4eqYFKxbhhHPrcw0tP8tWdOlg1ZSOfRCJBQkICpk2bVm0ZgUDA9fKqA+ru3bsRGBgIV1dXJCcn4+rVq4iMjMSyZcswfvx4jSf+Nm7ciJycHBw7dgz29vZ47bXXeMEnJCQEOTk5vO2XX37hneOzzz5DTk4OMjIy8NNPP8Ha2hpBQUGIi4vT1tvR6DIyMnD//n3s2LEDV65cwciRI3lhWX2P6u3arSxMmDqTt+jGwYMHkZOTg+vXr2Pp0qWIi4vDhg0bqr3m48eP0bdvXxw8eBDr1q3DpStX8cX3P+L27Vvo1asX73MAADc3NyQmJkIqlXL7ysrKsHXrVi6cPS8hIQERERE4evQo7t+/z+0fPHgwjh07xpu6Izk5GW5ubkhJSeGdIzk5GYMHD+a+njp1KuLj4zWm/SCEvBhjrNJ8fC/Oea+0t0dnVyuUyVXYcfZuY1ePvAA3LYsej9iwppxXZ3KVOuc1XQNfbXIeUHkeN8p5DVHXnHfzTjbGT53BW3SjoTnvytUMfPH9j8i8fZNyXgtS778O//77b5ibm8PIyAjvv/8+du/ejY4dOyI3NxdisRjW1ta88k5OTsjNzQUA5Obm8hr41K+rX6upTFFREe+b7HkrVqyAlZUVt7m5udX3FslTZzILUCZXwdHCCH7OFi8sbygSYninNgCAi3efNHLtSE2KyxVQP0ylr6uuAc+GcTyhHt5aU3A9vE0X/vbv3w8jIyP07dsXAKBSqeDq6or4+HheuWtpl9DV3Ra3bmeitLQUM2bMwOuvv47169eja9eu8PT0xPTp07F582bs3LkT27dv5x1vbW0NZ2dndOrUCfHx8ZBKpfjjjz+4142MjODs7MzbbGxseOewsLCAs7Mz3N3d8corr2D9+vX49NNPER0djYyMDK7ckSNH8P/sXXeYE/XaPTOTsr33xi4sy9IEQaUpRREQ7AhXXOTSBZErekVQEdFP1Huv2K6KDcVGU1G8CCogICJ1EZDe2/Ze0pOZ74+Z32QmmWQT2Bac8zx5YJNpmexOzrzvOee94YYboNfrkZycjLlz58oIxMCBAzFz5kzMmjUL0dHRSExMxIcffgiDwYAJEyYgPDwc2dnZslxaX3DgwAEMGjQI4eHhiIiIQM+ePbF3717ZMgkJCUhOTkb//v0xf/58HDlyBKdOnXJ7j+QRERuPkJBQmVU3NjYWSUlJaNOmDfLy8tCvXz/s27fP43E988wzKCwsxMaNG3HbbbehbVYmevbuh8WffwOtVosZM2bIlu/RowfS09OxevVq8bnVq1cjIyMD1157rdv26+vrsXLlSkyfPh0jRoyQZe0OGjQI9fX1svOwZcsWzJ07F7t27YLZzOd/mc1m7Nq1S0b+br31VlRWVmLr1q0e35sKFSqUcbykDiW1FgRpaVyfGdPg8hRF4fZrBJ4n5PipaBlwHIcaY+sesAY4C5Aqz/MdZHqt0qTrpoLPPO/wnzzPO3dW5Xke0BQ8LzJG4HmSoRtXyvPaqTzvqsRlXzU6dOiA/fv3Y9euXZg+fTr+/ve/48iRI415bJeFp556CjU1NeLj4sWLLX1IAY+tJ0oB8N1dX6f4dE6JAAD8WVDTZMelomEQ4hesZRDUSBldTYHIYD7nkeQH/tXAcRxYo9Gvh81gBEwmMFaz3+tKH/7k5m3btg09e/YUf6ZpGmPGjMGyZctky61d/RW6X9cLyanp+Pnnn1FRUYEnnnjCbXt33HEHcnJy3LqzUgQH89lQJMrhSvDoo4+C4zisWbMGAFBQUIDhw4fj+uuvx4EDB7B48WIsWbIEL774omy9Tz/9FHFxcdi9ezdmzpyJ6dOnY9SoUejbty/27duHIUOG4MEHH4TRaPT5WPLy8pCWloY9e/YgPz8fc+fOhVbruRDvy3loaOjG3r17kZ+fj169eim+zrIsVqxYgby8PCQlJQEg9msK+uAgPDRtOn766SdUVlbK1ps4cSI++eQT8eePP/4YEyZMUNzHqlWrkJubiw4dOmDs2LH4+OOPxd/BnJwcpKSkYPPmzQCAuro67Nu3D6NGjUJmZqao5P/9999hsVhk5E+n06F79+7Ytm2bx/OjQoUKZZBIlt5tY33mCl1SIgGoPK+lYbI5xAmsrdmxQSb//lWVfJfF8+oNPM+ztD6e9/3qlQLPy1B5ngc0Kc/zMHTjcngeTVHQMjSCgoMx5aFpKs+7SuB5gkIDIL5vAOjZsyf27NmDN998E3/7299gtVpRXV0tU/OVlJSIv0xJSUnYvXu3bHtk+q50GdeJvCUlJYiIiBD/CJSg1+uh1+sv922pUMCvJ8oBNJzTIkXXVJ78HS2qhd3BNmsXSoUTrX2yLgEhf3/VrBbOZMLxHj0bXtAFWgA1wuNy0WFfPqiQEJ+WPX/+PFJSUmTP5eXlYdGiRbhw4QIyMjLAsizWfvs1Js38J2wODidOnAAAdOzYUXGbubm54jKuMBqNmDdvHhiGwYABA8Tn165di7CwMNmyTz/9NJ5++mmvxx8TEyMLk3733XeRnp6Ot99+GxRFITc3F4WFhZgzZw7mz58PWsic6datG+bNmweAbyS98soriIuLw5QpUwAA8+fPx+LFi3Hw4EGx+90QLly4gNmzZyM3NxcA0L59e4/LFhUV4dVXX0Vqaio6dOggPj9nzhzxuACA5YB3P1uFdrcPQb3wXN++fUHTNKxWK2w2G6ZOnYpx48Yp7qesrAzV1dWyz4qiKGgZClYHh+ycDuA4DqdOncINN9wgLjN27Fg89dRTOH/+PABg+/btWLFihZv1AuAtHGPHjgXA23FqamqwdetWDBw4EADf5d2yZQueeuopbNu2DTk5OYiPj0f//v2xZcsW8fWsrCy0adNGtu2UlBTxGFSoUOE7tvqYuyxFZ4HnXaoyodpobdUqsqsZhDdpaAqhjRTE3xQgzdxalef5BS0AA4DjDS3oBU3B8/737deY+Mg/YXOwKs/zgKbgeRwHvPPZKtwzfDDIbPMr5XkA78KzOVi0a6/yvKsFjVZ5YVkWFosFPXv2hFarxaZNm8TXjh8/jgsXLqBPnz4AgD59+uDPP/9EaWmpuMyGDRsQERGBTp06ictIt0GWIdtQ0TwoqjHheEkdKAq4MTvO5/UyY0MRptfAbGNxukydhNNSqDa1/sm6gPP4VBtH64bJZEJQUJDsue7du6Njx45il3fr1q2oKC/DkNvvlk3q8tZJ1unkN4djxoxBWFgYwsPD8c0332DJkiW45pprxNfJ1HXpQykUWAkcx4mK5KNHj6JPnz4yhXK/fv1QX1+PS5ecOVPSfTMMg9jYWHTt2lV8jkRLSL/TGsLjjz+OyZMnY/DgwXjllVdw+vRpt2XS0tIQGhqKlJQUGAwGfPPNN7JzNXv2bPH978nfh1U//orO11wrU+KsXLkS+/fvx4EDB7Bq1SqsWbMGc+fO9Xpsrp8VyX3xNEUvPj5etGR88sknGDFiBOLi3L8vjh8/jt27d2PMmDEAAI1Gg7/97W9YsmSJuMzAgQOxfft22Gw2bNmyRSSFAwYMEMkkIYGuCA4O9qvLrkKFCsBotWPP2SoAvuXxEUQGa5ERwxcODhWo+dcthWrRqqv12W3TEnDGsvw1HRuBAl95XnkZ4XlOXqDyPDkam+ft2/cHVv24DZ2uuVYWy9I4PI8/PyrPu3pwWUq+p556CrfddhsyMjJQV1eHZcuWYcuWLfjpp58QGRmJSZMm4fHHH0dMTAwiIiIwc+ZM9OnTR6x8DxkyBJ06dcKDDz6If//73yguLsa8efMwY8YMUYU3bdo0vP3223jyyScxceJE/PLLL1i1ahV++OGHxnv3KhrENkHF1y0tCtGhvndpaZpCp5QI7D5biUMFNejgQ5afisYHIX+tXckX8RcPZKaCg9FhX75f65woqYPVziIrLhSh+ssWZYPyoox2RVxcHKqqqtyez8vLw7JlyzB37lwsW7YMt9w6BFHRMbA5WLFzefToUfTt29dt3aNHj7pN/Xr99dcxePBgREZGIj7e/aYzNDRUVJL7g4qKCpSVlSErK8uv9VztFRRFyZ4j5JFlWfiKBQsW4IEHHsAPP/yA9evX47nnnsOKFStwzz33iMts27YNERERSEhIQHi4+zU0Li5OPA+1JhtsoQYESYZuAHxgMlmmY8eOOH36NJ599lksWLDAjcjHx8cjKioKR48elb9/DQ1Y+c+KoijFcz9x4kQ88sgjAIB33nlH8T0vWbIEdrtdphLgOA56vR5vv/02IiMjMWjQIBgMBuzZswebN2/G7NmzAfDkb+LEiaisrMSuXbvw0EMPuW2/srIS7dq1U9y3ChUqlLHzTAWsDhZp0cFoGxfq17pdUyNxodKIQ4U1uLG9741gFY0Hwptac+4yIMnkU3mezzhTZoDRakd6TDAigy9fKdsUPG/wEJXnNYTG5nlGqx3mkHrZ0A2gkXiesL1jKs+7anBZSr7S0lKMGzcOHTp0wC233II9e/bgp59+wq233gqA/8O9/fbbMXLkSPTv3x9JSUmysEaGYbB27VowDIM+ffpg7NixGDduHF544QVxmaysLPzwww/YsGEDunXrhkWLFuGjjz7C0KFDr/Atq/AHxMLhT3eXQM1raXkEjl2XP76/ql2XoijQISF+Pey6ICA4GLqwUL/XlT786fxfe+21itmrDzzwAA4dOoT8/Hx8/fXX+Nv9fAfPznIYOnQoYmJisGjRIrf1vv/+e5w8eRLjx4+XPZ+UlITs7GxF4nclePPNN0HTNO6++24APBnasWOHrKO5fft2hIeHIy0trVH3rYScnBw89thj+Pnnn3HvvffK8k4A/nuwXbt2isTPFSYbyWnxbtdiGAZ2u10x84WmaYwePRrLli0Th2ABfIfXbDLh44/eFz9PVwwbNky0iih9T9vtdnz22WdYtGiRrDN/4MABpKSkiHk97dq1Q3p6Or7//nvs379ftO+kpqYiNTUVixYtgtVqVezwHjp0SDEEWsXVBYvFgtraWtlDxeWDRLL4k7tM0DlVzV9uaRDeFNXKeV6kyvP853l6vcDzwlodzxszJg8APxxE5Xme0ag8T5K77O0zvRyep2NomE0mLF3ygcrzrhJclvxDKrlUQlBQEN555x2PVV4AaNOmDdatW+d1OwMHDsQff/xxOYeoohFgd7D47ZT/eXwEXdN48ne4UCV/LQWR/LV6u+5fO5PPXzhYDizX/FPXhg4diqeeegpVVVWyKWeZmZno27cvJk2aBIfDgbvuugsXa+2wOViEhobj/fffx/3334+pU6fikUceQUREBDZt2oTZs2djypQpGD58uF/HYbFYZOQE4C0BUutAXV0diouLYbPZcPbsWXzxxRf46KOP8PLLL4sdyocffhhvvPEGZs6ciUceeQTHjx/Hc889h8cff1zMaWkKmEwmzJ49G/fddx+ysrJw6dIl7NmzByNHjvRrO+Q9AsDFCiPqLDaEJ8UAcGbvVFRUoLi4GHa7HX/++SfefPNNDBo0CBEREYrbfOmll7Bp0ybceuut+Pe//40uXbpg/+HjWPDcfNhsNo/f6wzDiJ1hhnEvNK5duxZVVVWYNGkSIiMjZa+NHDkSS5YsEa04gwYNwrvvvovs7GzRIgPwXd7//ve/YnCzFOfOnUNBQQEGDx7cwFlTEeh4+eWX8fzzz7f0YVw1uJw8PgKSv3xYLfK1GGrEWJbWnYkoNnP/oko+f8FxnGS6bvPZsH3leXffdSfOVttgZ1kEh6g8zxVNwfMKq4yoNtkQHB8FwKm6bgye9+exk3h23jyV511FUKchqPCIA5dqUGOyISJIg25pkQ2v4AKi5DtcWOvR46+iaVFtDAzyFynaddWsFl9gF7LuaIqSWTObGl27dkWPHj2watUqt9fy8vJw4MAB3HPPPQgP44tMDpYDy3K47777sHnzZly4cAE33XQTsrKyMHnyZMydOxcffPCB38fx448/Ijk5Wfa48cYbZcvMnz8fycnJyM7OxoMPPoiamhps2rQJc+bMEZdJTU3FunXrsHv3bnTr1g3Tpk3DpEmTZCHHl4vMzEwsWLBA8TWGYVBRUYFx48YhJycHo0ePxm233eZ34YK8x+TkZNzQpR1u6ZmLF597RrbM4MGDkZycjMzMTEydOhXDhw/HypUrPW4zNjYWO3fuxKBBg/DQQw+hXbt2mPz3sUhrk4Vv1m9B27ZtPa4bERHhkVQuWbJEtOa4YuTIkdi7dy8OHjwIgCd/dXV1Yk4LwYABA1BXV6fY3V2+fDmGDBniFtKs4urDU089hZqaGvFx8eLFlj6kgMWFCiPOlhugoSn0bRfr9/qdBZ53rsKIWrNavGkJBEosC+GhdRa7yGFUeAbLSZq5TViMcoWvPC8s1KkQtDtYlee5oCl4Xs9OPM976Xn5sTcGz5vw4ANIa5OFles2qzzvKgHF+TNXOwBRW1uLyMhI1NTUePylVKGM1zacwFubTmJE12S8k9fD7/UdLIcuz/0Ek82BjY8PQHZCWMMrqWhUzP7qAL7Kv4TZQztgxiD/sy2aCyW1ZvR6aRNoCji1cDjoZixctQTMZjPOnj2LrKwst7wMX2Cw2HG6rB56DY0OSc17Xfvhhx8we/ZsHDp0yGMXlOM4HC6sBctx6JAYDr2LhdRsNvNqv4sXsXXr1ka3a7Q0jEYjYmNjsX79ejcC0xTgOA6HCmvBcRxykyKg0zTuDYHJ6sDJ0jpoaBqdUlrf96jVakX79u2xbNky9OvXz691vf0tqvwhMKB+TpePz3eex7PfHcINWTFY9dDlDbbr98ovKKg2YfmU3uhzGYVCFVeGf/14DIu3nMb4vplYcGfnlj4cj7A7WGQ/sx4AsO/ZWxHjR853IOJKeZ7F5sDxkjowFCVOsm4u+MLzAOBYcS2sdhbt4sPcsqFVntf4OFpUC5uDRXZCGEJ0l5/FrQSbg8XRIj76oktqJOhWNsRH5Xn+Q1XyqfCIbSdJHt/lhSkzwvANADikWjlaBIGSyUeOj+WAequ9hY+m9YNMrW3O7i7BiBEjMHXqVBQUFHhchqIoMcTXpqDiDQoKwpo1azBu3Dj8+uuvTXasLYXNmzfj5ptvbjbiZ3Nw4jQ5bRPYerQaoVvPsmBboSr7woULePrpp/0mfipU/NWx7QqsugRdUtVolpZEoMSyaBga4UIhSHVtNAzCnZozkoXAF54HAFqBg9oUlJkqz2tcsCwnnmddE/xOaGhKpsxsbVB5nv9o3DKwiqsGHMfheHEdAKBnm+gGlvaMLikRyD9fhUMFNbj72tTGOjwVPqI6QMhfkJaBXkPDYmdRY7QhIqh1H29LoyVyWqSYNWtWg8toGAoWu2eyEBQUhLlz5zbykbUOjBgxAiNGjGi2/VmFc6xlKL+D830BQ1FgKAoOjoPVwSKI9j7co7mRnZ19WVP4VKj4q+N4Cc/zemRcCc+LxE+HS9ThGy0EknHX2gdvAPyE3TqLXeSmKjyDcKfWzPPEZq5Dufmn8rzGg7WJY3ooioKOoWGxO2B1cGhkoeAVQ+V5/kNV8qlQRFmdBUarAzQFZMSENryCB3RJVSfstiSc5K/12yJIIVIdvtEwbCwp6rTeS7iT/LW+juDVBqu96bq7gIsyU/08Vai4KmBzsLhUZQIAtI2/Ap4nZDarjo2WQbUweCOylTdzAXXCrj8ghTNtK46vIc4BlRc0PUiRT6ehm6SZC0g+T7v6eV4NaL13iCpaFGfLDQCA1OjgK8p3IkW+I4W1rdLmdbUjUOy6gLMQWa1OXmsQLa3k8wVO8qf+3Tc1pOSvqaDVeO/Yq1ChQg6WdWDLZx/ixM7fWvpQFHGx0ggHyyFYyyAhXH/Z2yFD1s6UG1BvUeM2mhuiXTeQmrkqz2sQdpYo+VrvrTo5ttZo7/QXHMehrrICprralj4URdiauJkLqM35qw2t98qhokVxvsIIAMiMvfzuLgC0TwiDXkOjzmLH+UpjYxyaCj9AOryt3a4LOLvQ5JhVeIadbf6Ja/5CJQvNB5H8NWWRT+3Yq1DhF4pOHEf+D2uw9YuPW/pQFEF4XpvYkCtShsSH65EUEQSOgxjcrqL5IE7XDQCe52zmqjyvIajN3OaFw2aDoaoSteVlLX0oirA2B88Ttm1Ved5VgdZ7h6iiRXG2glfyXWmRT8PQyE1Wh2+0BMw2B8w2/kIdCOSPqA1VJV/DsEky2ForiMXkaiB/rR1NbdeVbtuq2jhUqPAJdZXlAID6ykpwXOu7DhLHRlbclfE8wDl8489LKs9rbhBVXCA4NiIIz1Ptug1C5HmB0MxlA58XOOy8CpljWbCt8P00h2NDdxUVbVWoRT4VHnBOIH+ZjUD+uqaqRb6WQK1AomgKCGttCaoKiFKzWnyG2OFtxeTvarJxtHY0i11XVWaqUOEXjNVVAADWYYe5vq6Fj8Yd5yoaj+eRaJZD6oTdZoXdwaJOsEgHwuANNXvZd4iOjdbczJUUhVpjI8MfsA5n1ABrb32xA83RzFV53tWF1nuHqKJFcU6064Zc8bZIXotK/poX1ZI8ProVB/cSqOTPN7AcJ8lqab2fq7PDG/jkrzWDZTmRkDUP+VM/SxUqfEG9UOQDAIPk/60FTcHzDhc0vV2X4zgc2LAeJWdONfm+Wjtqzc5iRCAo+cRmrurYaBBOu27rvVUnx8ZxHBwBnrvOOhyK/28taNZmbiM7Nkx1tbCaTY26TRUNo/VeOVS0GDiOw/mm6PAW1Ko3+80IYnuNCmn9YcyA1K6rZrV4g0MgfhQoaFpx8ZYUIDmOEzvSKhofhPjRFAWmCX8ftBpnJp96HVehomEYpUW+qlZY5CtvnFgWwMnzTpbWwWRt+Aa5urgIq154Gmf/2Ov3vgqPH8XGj97BT++96fe6VxsIXwrTa1p1MYggUrXr+gRpM7c1T9elKUp0lAR6A1Cq3pOq+loD7CwrFlG1zdDMdXAcHBLLssNuR2VhwWUp0u1WK2pKS1BTUtxox6nCN7T+bwQVzY7SOguMVgdoCkiPvvIOb05iOLQMhRqTDZeq1Ep+c4Eo4iICoLsLAJFCMVJV8nmHTaLiu5Kw9MtFRUUFEhIScO7cOa/LScmfatltOtgk3d2m/H0g5I9tBR37I0eOIC0tDQaDoUWPQ4UKb6ivqhT/b6hpXUU+q53FpSpeydcYmXyJEXrEhenBcsDR4obVfMd3bMPFwwexf8M6v/dVW14KAKi4dBEs67/ipuLSRdSUXh03nDWmwMnjA1THhq+wS5q5Tdm88wRfeR7gbOgGei6fQ6Lec7QyJR9R1mloukl/HxjaKR6wSoq2FqMBVpMRhhr/HXkOu0341+6XQpLwvPLiIlgMhlaZk9jaoRb5VLiBdHdTo4MbRRas09DokBQOAPhTzeVrNpAObyDktADO41QHb3iHM4+vZbq7CxcuxF133YXMzMwGl5Xmtfz+++8YPnw4oqOjERQUhK5du+K1115zI1MURYmPyMhI9OvXD7/88ov4+vjx42XLkMewYcPEZTIzM8Xng4ODkZmZidGjR8u205qxZcsW2XtLTEzEyJEjcebMGXEZ8h4jgnXolh6NDkkRoCgKr7zyCgDg3Llzsm3odDpkZ2fjxRdflCnxFixYgO7du8v2X1lZiVmzZqFNmzbQ6XRISUnB5EmTUFZUAMCpHiSfxbRp09zew4wZM0BRFMaPHy8+58tnBwB//PEHRo0ahcTERAQFBaF9+/aYMmUKTpw4AQDo1KkTevfujddee+3yT7IKFU0MYyu2616qMoLlgBAdg/hw/RVvj6IocfiGL/nLpMhWX1nh976Mwo0m67CjtrTUr3WtJiO+fPoxLH929lWhSCaKuKgAGK4GAJHqdF2fYG/hZq5/PI80cwOb5zV3Jp8/PC9Er0W39Gh0To1sUp43ceJEkeeRwuL48eMRGhmFJ5+d76Zw9IXnBYWGITk7B2MmTILD5ry/85Xn/ftf/0JVcSE4tcjnN9Qinwo3nGukybpSdBUtu2qRr7lQE3DkT+3w+gLSLW1Kyb4nGI1GLFmyBJMmTfJpedJxXPPddxgwYADS0tKwefNmHDt2DI8++ihefPFF3H///W43W5988gmKioqwfft2xMXF4fbbb5cRn2HDhqGoqEj2WL58uWwbL7zwAoqKinD8+HF89tlniIqKwuDBg7Fw4cIrPAvNh+PHj6OwsBBfffUVDh8+jDvuuENGll944QXsP34Gm/KP4Y9jZ1BUVISZM2fKtrFx40YUFRXh5MmTeP7557Fw4UJ8/PHHHvdZWVmJ3r17Y+PGjXjvvfdw6tQprFixAqdOncLfhg/CpfPnZLac9PR0rFixAiaTU6VtNpuxbNkyZGRkuG2/oc9u7dq16N27NywWC7788kscPXoUX3zxBSIjI/Hss8+Ky02YMAGLFy+GvRUGZKtQAbhk8klUfa0BhOe1iQ1ttCKCPzyvpowvzl1ekc95XquEG1JfUV1SDJvFDEN1FWxXQUZUjVHleVcjnHl8zV/g85fnkYbz92u+DWie11KZfL7wvD9PnsWm/GPYc/h0k/O8kbcNFHies6iWmpqCNWt/gKG+XvwcfeV5p48dxYEd27H4jddgt/HFfV953rgHH8Rny5bD4XCAZpjLO8F/YahFPhVuIGHMjWHhIOgshDKrSr7mg2rjuDrRkuRv3bp10Ov16N27NwCAZVmkpaVh8eLFsuX++OMP0DSN4sJLMBoNmPXIdNx555344IMP0L17d2RmZmLy5Mn49NNP8fXXX2PVqlWy9aOiopCUlIQuXbpg8eLFMJlM2LBhg/i6Xq9HUlKS7BEdHS3bRnh4OJKSkpCRkYH+/fvjgw8+wLPPPov58+fj+PHj4nJbt27FDTfcAL1ej+TkZMydO1dWOBo4cCBmzpyJWbNmITo6GomJifjwww9hMBgwYcIEhIeHIzs7G+vXr/frXB44cACDBg1CeHg4IiIi0LNnT+zdK8+nSkhIQHJyMvr374/58+fjyJEjOHXKGTYfHh6OqNgExCUkIi0lBUlJSQgNlV+3Y2NjkZSUhDZt2iAvLw/9+vXDvn37PB7XM888g8LCQmzcuBG33XabeP5++uknaLVavDTvCRn569GjB9LT07F69WrxudWrVyMjIwPXXnut2/a9fXZGoxETJkzA8OHD8f3332Pw4MHIyspCr1698Oqrr+L9998Xt3PrrbeisrISW7du9fGMq1DRfHDY7TDVOW2rrU3Jd7ac8Lwrj2QhcPK8hu26taUlAABjTbVo5/IVxlonj/S3yCctKprr6/1atzUikHne1aCkbCqQ71gt3fy36f7yvKJLF2E0GvD4zBkBzfPmzHsWz764ELk9rkP7zl1aFc+Ljk3keV5qcovwvGs6d0FKcjJ++PEnsQDqK8+Lj4tDQnw8oiIj4bDZ/OJ5Nw8aiOrqauzcm98iitZAh1rkU+EGYtdt0wRKvsOF6vCN5oI4eCNQyJ9g46j6C9o4OI6DzeLw6WE22eCwOgC77+t4e/jz97ht2zb07NlT/JmmaYwZMwbLli2TLffll1+iX79+yGzTBju2bkZlZQWeeOIJt+3dcccdyMnJcevOShEcHAwAsFqv/Pfi0UcfBcdxWLNmDQCgoKAAw4cPx/XXX48DBw5g8eLFWLJkCV588UXZep9++ini4uKwe/duzJw5E9OnT8eoUaPQt29f7Nu3D0OGDMGDDz4Io9Ho87Hk5eUhLS0Ne/bsQX5+PubOnQut1vPfqqfzYLX7PnFt7969yM/PR69evRRfZ1kWK1asQF5eHpKSktz2//dJU/H71l9QWlYue23ixIn45JNPxJ8//vhjTJgwocHjccVPP/2E8vJyPPnkk4qvR0VFif/X6XTo3r07tm3b5vd+VKhoahhrqwHJtbW1FfmahOelCcM3SupgtnlWwrCsA7XlZeLP9ZX+qRyNNdXi/ysL/Svy1VU4r11mQ+AX+QjPIzbY1g5S5LM5OBh8GNByNcEvnme28zzPwbZ+npfJ87yqAOd5q75ZjZjoaKxb/TUmjf976+J5pOjbDDxv4uSHeJ5X7myIcByL++8biZXffCNadn3leVKLr91m9YvnaWganTt2xK69+Q3uR4U7NC19AH9VmOvrsfbNf6HjjQPRecAtLX04MpwVyF9jdng7JIVDQ1OoNFhRVGNGSlRwo21bhTJIVktkgEzXjQnjj9NsY2Gw2BGq/+tcnuxWFh882jKKpKlvDoBW75sM/vz580hJSZE9l5eXh0WLFuHChQvIyMgQCcS8efPA0BTOn+U7kh07dlTcZm5urpjB4Qqj0chvh2EwYMAA8fm1a9ciLCxMtuzTTz+Np59+2uvxx8TEyMKk3333XaSnp+Ptt98GRVHIzc1FYWEh5syZg/nz54MWuujdunXDjEkToQ8JwVNPPYVXXnkFcXFxmDJlCgBg/vz5WLx4MQ4ePCh2vxvChQsXMHv2bOTm5gIA2rdv73HZoqIivPrqq0hNTUWHDh3E5+fMmYOnn5kHACARjevXr8dNN90kLtO3b1/QNA2r1QqbzYapU6di3LhxivspKytDdXW158+qYy44jsPpU6fRKStVfH7s2LF46qmncP78eQDA9u3bsWLFCmzZssVtG94+u5MnT/L7Ec5JQ0hJSRH3qUJFa4Kxulr2c6sr8gl23axGLPKlRAYhOkSLKqMNx4vr0C09SnG5+spK2Y1ffWUFIhMSfd6PtMjnv5JPUuS7jEmRrQ3VJiF7OUDsusFaBkFaGmYbi4p6C8JUntcsaEqep2ECn+dxHIdOHXPx2IyHAQD/mPYQ/rv4vVbD8555Zh44NBPPy+0IjuNw5vRpXNMuDRzHgeM4jLzrLrz86iKcOXMGQSGhvvM8jgMH/pw+8dgsv3iew25HYmICCvxs5qjg8de5urYynD2Qj/MH/4CxprpVFfk4jsN5wa7bmJl8QVoG7RPDcbSoFn8W1KhFvmYACTYOFBtHmF6DEB0Do9WB0joLsv5C5C9QYDKZEBQUJHuue/fu6NixI5YtW4a5c+di69atKC0txahRo5yMBPDaSdbp5IXoMWPGgGEYmEwmxMfHY8mSJbjmmmvE1wcNGuRmHYmJifHpPXAcJ8r+jx49ij59+shsAP369UN9fT0uXbokZo107tQRFqMBdqsFIZFRiI2NRdeuXcV1EhP5G9RSP0LgH3/8cUyePBmff/45Bg8ejFGjRqFdu3ayZdLSeIJlNBrRrVs3fPPNN7Jz9c8nnkDfYSMBAO0Tw8HQFFJTU2XbWLlyJTp27AibzYZDhw5h5syZiI6OFoObPZ0jJdDCeXK4vB4fH48RI0Zg6dKl4DgOI0aMQFxcnOI2vH12/qq8g4OD/eqqq1DRXCCTdbX6INgsZtkQjtYAMXu5EWNZ+OEbkdh2shyHCms8FvmIVZegvsq/XD6DrMhX6Ne6dRVSu27gF/lqjIFl16UoCgnhQbhQaURpnaVRlaQqGgf+8jxGYikOWJ7HcejUoQMomgbHsqCAVsPznnjiCfS97T5wHIe28aHQaZgm5nn8v2T4Cxl4ERcbg1sGDcTnn38OjU7vM8+rLCqEw2pFVFQk7DabX1NyWbsdQUFBMJstPq+jwgn1LrqFUC9YBupbWRhzaZ0FJpsDNAWkRTeekg8AOibxRb5TpfUY2rlRN61CAbWmwLLrAkB8uB7nK4woq7M0aiZka4dGR2PqmwMaXhDAieJaWB0ssuLCGkXtqNH5ntoQFxeHqir3m9W8vDyR/C1btgzDhg1DbGwsaoxWZGTxhObo0aPo27ev27pHjx51m/r1+uuvY/DgwYiMjER8fLzbOqGhocjOzvb5uAkqKipQVlaGrKwsv9ZjhMBf1uEQyaPUckHIoz/kZcGCBXjggQfwww8/YP369XjuueewYsUK3HPPPeIy27ZtQ0REBBISEhAeHu62jejoGGRktYWGptEhJUJxP+np6eK56tixI06fPo1nn30WCxYscCPy8fHxiIqKwtGjRxW3derEcVAUhbQ27udv4sSJeOSRRwAA77zzjsf37e2zy8nJAQAcO3YMffr08bgNgsrKSjfCrEJFawBR7sW3yULhiaMwG+pht1qh0bW8st5qZ1FQxQ+dyIxtZJ6XHIFtJ8txssSzFbamTF7kk1poGwLHcTDVODP56irKYDOboXW5lnlCnUzJF/h23ZoA5XkXKnme91eCPzzvdFk9TFY7MmJCEdEIn21T8jyDxR7wPI/jOGi0Wmh0OtjMZgBoNTwvJjYO6ZlZoADkpkaKzVYpGpPnnXTheRznfL9j7huJef+3EBRN+8zzyrQMHEL+IceyaJ/N/674wvMcDjuqq6vRPqeD1+VUKEPN5GshkOKeqbYGdlvrGTRArLpp0SE+ZTz5g+Qo/kJTWmtu1O26Qs3841EdYNN1ASAhXA8AKK1r2t+R1gaKoqDVMw0+NDoarIYGo2MQEqLxaZ2GHv6E2V577bU4cuSI2/MPPPAADh06hPz8fHz99dfIy8sDADAMjb4DbkZkdDQWLVrktt7333+PkydPYvz48bLnk5KSkJ2drUj8rgRvvvkmaJrG3XffDYAnQzt27JBdM7Zv347w8HCkpaU5V2T51zmOa9Spazk5OXjsscfw888/495775Xl2gFAVlYW2rVrp0j8AMAuHLc/12qGYWC32xWzb2iaxujRo7Fs2TIUFxfLXjOZTFjywfvoO+BmhEdGu607bNgw0SoydOhQn49Heu6HDBmCuLg4/Pvf/1ZcttrFAnno0CHF0GcVKloahmqe48WkpoHR8M0Yqc20JXGxygiWA0J1DOKF79zGQnKkwPO8fIfXlMqvLf5M2LWZTeKERq2e31dVse9qvvqrLZMvkHleE98LtDb4yvO0egZgKDA6BsHBAcDzaIrneVEBzPOE1xhGA1rDyJ67Ulwpz3MIRUUtQysW+JRwJTzvww/ek/E8jnWeh0H9+/vF86ScmRIUn4MGDvSZ5znsdhw/cRLXuhSIVfgGtcjXQpCSGkMrUvOdbwILB0FiBE/ISmq9d+9sVgtO7d0ldlP8QWXhJSyekoedq1de1jFeTRAHbwQU+eN/R/5qHV5f4WA5kahoWmDq2tChQ3H48GG3Lm9mZib69u2LSZMmweFw4M477xSOkUJISCiee+UNrFmzBlOnTsXBgwdx7tw5LFmyBOPHj8eUKVMwfPhwv47DYrGguLhY9igvl6tB6urqUFxcjIsXL+LXX3/F1KlT8eKLL2LhwoVih/Hhhx/GxYsXMXPmTBw7dgxr1qzBc889h8cff1zM4wPknUxpltTlwmQy4ZFHHsGWLVtw/vx5bN++HXv27PGYkeIJNTV1KC8tQXV5qXgeamvlky0rKipQXFyMS5cuYf369XjzzTcxaNAgREQoK/9eeuklJCUl4dZbb8X69evF8zd06FDY7TY8/eKrcLBS8svBbKgHBb5bf+TIEVH5qATpZ1dw6RIO792Ncyf4KXihoaH46KOP8MMPP+DOO+/Exo0bce7cOezduxdPPvkkpk2bJm7n3LlzKCgowODBg/06ZypUNAcMwo1KWHQMQqL4m6XmdG7UlpWi8ISyUkM6dKOxJxb6wvNqy3i7W3AEP6ijzo8iH7HqavVBiMtoA8B3yy7HcfLBG1eBXZfEsjSG2qu5QIp8ZfUqz1MCx3GwCd+xGiZweN6zr7wesDyPT40DaIYBzWiE564M/vA8h90Oq8mkKFKprhV4XkVZ8/A8m5PncRwn2nVphgHDMPh9y2afeV5RYSFKSktRWlaGWgMfrRKk0/nO886eQ1FJCW5Red5lQS3ytRCkRb7WZNk9W07y+BrXwgH4rtL6Y/3/sOY//4c9//vG731cPPwnTHW1OLb98sJtrxYVIMtyqDXzRb5AIn/x4u+ISv6UYBeIH0NToOnGvTnzBV27dkWPHj2watUqt9fy8vJw4MAB3HPPPeKEMEY4xluG34lffvkFFy5cwE033YSsrCxMnjwZc+fOxQcffOD3cfz4449ITk6WPW688UbZMvPnz0dycjKys7Px4IMPoqamBps2bcKcOXPEZVJTU7Fu3Trs3r0b3bp1w7Rp0zBp0iTMmzdPti2pPcNh903Jl5mZiQULFii+xjAMKioqMG7cOOTk5GD06NG47bbb8Pzzz/t4Bnj8a+ELuKVnLq7v3E48D64TywYPHozk5GRkZmZi6tSpGD58OFau9NwEiY2Nxc6dOzFo0CA89NBDaNeuHUaPHo127dph+45dSGuTKSs2O+x2VBcXob6qEhERER5JJYH0s0tLT0fXG3rj1tuc5P+uu+7C77//Dq1WiwceeAC5ubkYM2YMampqZNPwli9fjltvvVXMTVShojWBZPCFREUjLIrPkTLUeM7ls1nMsFkaT9n03X/+D8ufnY0j2za7vUYcG5mNOFyNwBeeVyNk8qV26ATAPyWfUbDqhkRGIiaFV+H4OnzDajLKzvHVUOSrMfFNp6gAma4LSHheAw3/vypkzVwmMHgeBeDWEXdhw8ZNAcnzyPmmNYykeOX5fpBlWbAs22g8r6a0GJWFl2CsrXF77eX/ex639MxFn67ZzcLzdu3ejbQ2mQDI7yLPf3VB/OcdFhLsM89LTUtDtz790K1PP4y4515+m1arTzyP4zisXrMGA268EW3btfW6PxXKUDP5WgjSoGF/CE5Tg3R4G3PoBkGCj0q+svNnAQDlF/2fmkgsMlVFhXDY7aJNxhdYzSZ8MfdRpOR0xLCHH/N7360JdWa7qDQPlEBmwEn+VCWfMuwO/su2JVR8BPPnz8fs2bMxZcoUmdpt+vTpmD59umxZRlKI7NvvRvz4448AALPZjLvuugtLly7FhAkTZHaNhgrtS5cuxdKlS70uQ6aq+YIBAwZg9+7dHl/fsmULKi5dgM3C/06yDrvi9qXHbTQaUVJSgoEDBypuU6f80ozZAAEAAElEQVTTYfny5R73OXDgwAbPw7lz53C23IA6sw2p0cGIDZXb7jIzM31qWixYsMCNpMbFxeGtt97CW2+9JXueZTkcKqwBBw4sx38WteWlMNbUwG51/5v97rvvZD+7fnaGmmrUlZfx23Y4QAvk+rrrrsM333hu8litVrz33nv473/+hdJzpxHfpq3sd1GFipZGvcBFwqKcSj6DQs4VwBf4Pn50KoLCI/Dgv94ETfs2BdMTHHYbyi/w/GnDB28jPiMT8ZIczaYYrkYgVfJJw++lEIt8uZ1was8OP4t8QvE0MgrRyXz4fFXhJZ/Wdc3+C/RMPo7jUBNg03UBp2NDbeYqQ9bMbWSlra/wh+dRFAWGpmFnWfQJUJ73v6+/hsVoAM1oRCXf4f37ERYtH/RBJs1WXDwPg8nUKDyP4ziUCTWB+opyaHV66IQC6rlz53Cx0ogqoxWJEUHi9ZWgKXgeABwuqIGD4+BgOby16FXYLRZog4JgNtSL+XoE3nie1WREZWEBNFodQqKiUFtWKkaUNcTzzCYTPl22HO++vkj8TFT4B5UVtwA4lkV9pVO916qKfIJdtymGHpCLU2md2etFqVrIVyE3f/6AhF2zDjuqS4r8WrfkzClUFRXi5O7f/d5va0O1QPxCdAz0miu7YWhOqEo+7yAWDm0LdHcJRowYgalTp6KgoGH1BE1RYqHPLrF4BgUFYc2aNRg3bhx+/fXXJjvWxoKU1LD2hu26mzdvxs033+yR/DUWrHahw9pMlh6KcoZPk5wYh0DYXImfL5CeS5Kz5QsuXLiAObNn44aePUFRtFrgU9HqIFPyRQtFPg8TdisuXUR9VSXKL5zDhUMHr3jfNaWlovrCbrXg+0UvyfLnmmKyLgH5DrfaWXEohBQOu03kvKm5TiUf52OYvVPJF4Xo5BQAvtt1612LfAGeyWe0OmBz8N+rajP36oFNaOZqW/B7zR+eBzgbunZHYPI8EsNCSzL5PEWzOOx22G02bNu2DQP6979inscJqkCALyJWlxbL+JRV+H1o7Jx8byCfp4PlwAocTyso+fjj9c3RQvL4aIYBIwwxcfjI9c6dPYt/TJ+GPr16NXqsxF8FKjNuAZjq62QXD6mqryXBcZzY4W3TBHbd+DD+i93m4FBl9DxspLqYL87VXkGRDwAqL130a12SE2M1meCwt55hKJcDQq4DifgBf91AZl9BCFRL5LRIMWvWLKSnp/u0LFEdynPceAI4d+5cjBw5stGPrzHhOmzDl2LWiBEj8MMPPzTlYfG5Pc1M/iiKgkZC/gCIXVnWbvc77kB6Xu0KAdGekJ2djYkTJgAAaD/U2ipUNAc4jhNVe2HR0QgRAsyNHop81ZLBEcd+23LF+68u4bcXmZCIiPgEVJcUYf07r4mFtLNN6NgI0jKiqkzJtVFXXg6OY6HR6ZGQ2RagKLAOO0x1tW7LKoEMLwmJjEK0YNetLLrk07WHZP8Rh0eg23UJz9MyFEJ0ajP3aoGdbTmrrhT+8TzSzJUX6wOF5xEuwmicmXysh2gWUqQaPGgQln/6ieIy/oBwKJphoNHpwNrtqCktFq9ptmZu5gLSoq1DLEBqdDpxeIanc+MKaZFPIxT57HabLOfaE7Iy22DcmPtVjncFUIt8LQBX5V5rUfKV1FpgsjnA0BTSYxq/yKfT0IgJ5XNDPOW1mOrrxO6qsabarxs/QF7kq7h0wa91a8tLxf8Huo2DDN0IvCIfr/YsVwOZFWEXO7yB09VSUvIFElyVe40xeKMxYGc5sBwHCvzUteaCtMPLcZzYELmcycPSc+nw81rPCvv1J5JBhYrmgNVkFJWpvJKPt3wRC68rqkucEw5P7Pr9irP5qoWJifFt2uLOx58Go9XiTP5u7PruK1jsDhRWmwA0TSYf4D2Xj1h1I+ITwGi0CCHDN1xUdp5grK0GAIRERCEqKRkAYDEYfCoSkn3EpvEDO64enqcLKKVLQgT/+1FpsLg1/1RIeF4LN3P9ASlIBuLnKeUuZLgEADg88BmHTaKyMxrhuEJOSNwQGp0OUYnJoGgaVpMJ9RXlYFugmQtIeLukAEnTtMi3fHVuSM8rzWhA0RTAyc+hJ5B9MKpV97IROFeQqwhuRb5WouQjFo606OAm+3Ih5M9TLl9NsdxiW1fpG/EjkGbeVBT4p+ST2oNNCuGngYRqU+BN1gWcHd4Kg1UkOiqcsLWSDq8/8NThDRS4EjhfB280NYhVV8vQzZrbIy3aOuw2WTa1v5ZdKYn2x64r3RejCaxrnIqrH2SYmj4kFFqdXszk86zkc/Iem9mE0/mes6N8AVHyRSUlI7FtNm6ZxGdobV/1BfK37wTLAaE6RnRXNDa8TditKeOLfJHxCQCA8Ng4AL7zYKMwtTgkMgpanR7hcXzOV1Vhw7bCeoFPkqm8ga7kqw7APD4AiA3Vg6YAlgMq1IauG2yOwON5gdzMZVmHc/CGJJPPo11XwlU4joOl3nBF+yfbYzRaaHQ6RCYkAuAziw21deDAR99omrG5LzZzhSIfsdoSVZ2vzW5pkY+iKDBaXujjC98jDXZVyXf5UIt8LQBS5NMFh8h+bmmQoRttmsDCQeAkf8qd6iqXHD1/cvk4jpMr+fws8kntwaYAJ3+BateNCdWBoSlwHF/oUyGHOHgjkDq8hCw4Ao/8AU6iIdoUWomSj+S0aJuxuwsADOXs2BMCSMD6GXMgy+TzU8nnUJV8KloppHl8ABAaFQUAqPdU5BN4D8mYO3qFlt0aQRkYlcgr3boOGoKutwwFOA67P/kvghxmtIkNbTL1F1HkK/G8WqHIF5GQBAAIi4kF4DsPJtMnQyJ5BaA/E3aJXTc+IxMAP/AkkKNZagOU5zE0hdgw1bLrCWIsSwBlzbrGeAQSiPWUFKKkmXxKMQB24ZpB7KdXer8ochlhe0GhYQgljaGKUjAcCy1DN6taV/w8XZqpRFXnu5LPmXUIOM+ZK3dUgnPfKse7XATOFeQqAulYJrVrL/xc6XeWUVPgLBm60QR5fASJEd4z16TZNIB/uXxml6zDqoJLPoeDuu7L13yY1ooao9DhDda18JH4B4amEEss3Q1MYf4rgnR4A8quywRuhxdwqs20ev7GlXU4fA6Jb0o099ANAimZdyVq/ij5lLIO/bleqwRQRWsFKeaFiUU+3q5rrK5WvHaQIl+ve/4GADi3P/+KOEiVoAwkRT4AuHn8Q4hMSITDVI8kS3GTDFcj8MbziF2XqFXCovkiX12Fj0U+IZMvNDIKACTDN3xQ8hG7bnobfooQAtuyS+y6UQFW5AOcGd3q8A132Fii0g8gnicUJO0B2Mx1LUSRfzmWU8yOI7yHXNdtZpNoa70ckHVJAQzgmx8avR4cx0HLWpvVqgs4lXycQ86zRCWfj1zPIVHyAYDGHyWfQ1XyXSnUIl8LgHQsSZHPbrHAYrwyuW9j4Hw5P3SjKSauEZAOr6fuXbWrXbfC9yKfQWKR0Wh1sNusqC0tbWAtHhzHyVSD5rrAVvKJ5C/AbByAM6+lrF4dvuEKYnkNSCVfgBb5CJnR6Jy5R56yWpoTYpGvuckfyd7hODdi60+RT1rgIwTQYfWdKDutHIF3jVNxdcOTko912N0mutrMZpG7tOvZC/GZbcE6HDix87fL2jfLOlBbKij5kpxFPo1OJ6reQhymJsvjA6SZfH7YdX1V8kkGbwBAdHIqAKDSB7suiX+JiItHUGgYgAAv8hElXwDzPE/53H9lOJV8gVPkC+RYFtFSKij4aJr2OGCC45zNTW1wkOjIuxLrv6slFuCHnGl1fEGMBtsCRT5+f2KRTzg2MZPvMuy60u34peRTM/kuG4Fzp3gVgZCZqKQUkWg0p2V3+6ov8MNb/4HNLP9yJZl8TTFxjYB0eD3ZdUkAdWxaBgD/7LoGIaslLCYW0ak8ma0o8G34hqm2Bnark5AGupKPTC+OCMAOr1gIVpV8MrAsJxbKAon8iR3eAC/yMRqN313MxoChugrVxUVuQy2sLRDGDDjtunaHc+iGRiCj/pwXZ5eWEdf3NZeP41hVyaei1YJk8oVF80U+RqNFUHgEAGczkqBaKMgFhYUjKCwMnW4cCAA4sm3L5e27ogIOux00o0F4XJzsNTLlN8RhbLFYllpRySe36/qSv+yw28QiabAwsCNGKPI1pOSzmk2wGAzCPuOcRT5D4Bb5qgTHRqDZdQFnIVhV8rkjEJu5TAAP3iBcRFpMIsM3XHmXaOGl+Ot6cHg4AL7IdzmOPJZ1SCb7yv+OSWGM5rhmd2wQJR/Fyu265Jh85XquRT5flXwcx6mZfI2AwLmCXEUgBb2wmFiEkqlrVcpT1ziWxdYvPsaRX39plH3brBbsXL0Sx7Zvxbq3XxXtUSzLOYt8Tank8xLIDDjtuhldugHwz65rECbXhUZFIzaVH/teccm3XD7X/QR6ka/SwJ/fuLDAsusCqo3DEwjxoyhK/AJuCVRUVCAhIQHnzp3zaflA7vACzo4lzWiceSQeupgcx6G+sgLGmsYZ3MNxHOqrKmE21KO6pEhmHbG1kF2XUbDrkm62X0o+oUPOMBpnkc/HXD4y/ISiKNgdDmRmZmLv3r0+71uFiqaEqOQTimqA015KmpEExKoblcgXvTr06w9QFAqPHxGtrf6AbC8yIRE0zcheCxEUhcEOU5PadT3xPJvVIuYmRxC7rh+ZfCSPj6JpBIfxN9fRKXyRr7qkyKvd35mFHQx9SAiCwoiSL3BdG5X1/PUyrokGqDQl4r2oPf/KkDVzW9Cue/k8L/CKfA67vBDF/195wASZCstotKAoCvoQPtvUbrXKhCI+79tG+CUj27/0GFpGyUeKfKQAqZH96wvXY1lWjKdwVfKxdodbAVW+rnMYCqNhYLVaVZ53GVCLfC2AOrHLG9MgwSk4cRR7/7caP7//VqMUnqqLCgHhD+fUnp3YtuxTAPwXrdnGgqEppEUHX/F+PIF0eJWyWqwmo2jFSO/cFYC/Sj6ePIZGx4hKwIpLvin5asvltt5AJn6Ac2hFbGjgkT+njUMlf1JI8/iaM4DXFQsXLsRdd92FzMxMn5YnZGHvzp0YPnw4oqOjERQUhK5du+K1115zs75SFCU+IiMj0a9fP/zyi7PJMX78eNky5DFs2DBxmczMTPH54OBgZGZmYvTo0bLt+Aqnko9pUMnnsFlRX1WJ2vJSn+wInrBlyxY+AJqmkdQ2G1179cGDEyfh4J69fIeT43DLDV3QLT0aYUFa2Xl45ZVXAADnzp2TPa/T6ZCdnY0XX3xR1nFesGABunfvLtt/ZWUlZs2ahTZt2kCn0yElJQUTJ07EhQsXZEW+GbMeQ3J2Dv45Zy7/nCTEfsaMGaAoCuPHjxefk352QWFhSM7OQVx6G5y/WIBPly1HSptM2CXntr6+HlqtFgMHDpQd3y+/bEJydg4uFBRAr9fjiSeewJw5cy77fKtQ0ZgQM/mEJi4AMUidNCMJSERJpJCfFx4ThwyB/xzbvtXvfVcXy4uGUugFNWGIw9Qsjo2yOovsWkPiU3TBwaKSzq8in9A8CYmIFO104XHxYLRaOGw2r3yxTsjjC4vh1Y1BYU4FTqDCyfMCr5lLHBtqM1cO0gylKUpUzbcE/OV5pMiXvzvweJ5S9hux7roeN1GgidNmGQb6UP5a6m/M05YtW6ALCkJydg4Ss9ohMTERI0eOxJkzZ8RtXz9gELKyMhAVomtWnqehKdAcC3AcHn1yDrR6PaZNmyYpfjrAcaxXnscwDJKzc5CcnQNGo8GpU6fwwYcfIrvbtbDb7SJfVOJ5rN2O33fuQnJ2Ds6cOQudTqfyvMuAWuRrZthtNpiFYl1YTGyDBKey4BIAvmp+pRPXAGduCbko7f3fahzc+CPOCpN106ODoW1CZYgo0a+3gHXp+BCrbnB4BOIzsgAAtRVlPkugr0jJVyYv8gW6kq+CdHjDA6/I5+zwqlktUtjF7m7LXbaNRiOWLFmCSZMm+byOhqawaf1ajBs5HGlpadi8eTOOHTuGRx99FC+++CLuv/9+t7/xTz75BEVFRdi+fTvi4uJw++23i8QHAIYNG4aioiLZY/ny5bJtvPDCCygqKsLx48fx2WefISoqCoMHD8bChQt9PnaO4yTBwRowGu9WBbskU64xriF/7t+P/b//hg/f+S+OnzyJ0Xl5qK0oh02w6s544mkUFhbKzsPMmTNl29i4cSOKiopw8uRJPP/881i4cCE+/vhjj/usrKxE7969sXHjRrz33ns4deoUVqxYgVOnTuH666/HxfNnATiJcWpyMr765huYzGawDgdYloXZbMayZcuQkZHhtn3y2Z06egQHdmzH8T8PIrt9Nvr17oV6g0HWqd22bRuSkpKwa9cumCXxEls2b0FqSgratcsGAOTl5eG3337D4cOHL/NMq1DReHDN5AMgujYMLhN2a8hkXUl+XscbBwEAjmzb7LcFTFQGJqW4vWZieMVtOGdqMpX/uYN/4H9zH0KG8QKsDlbMBwack3Uj4xPFRlW4wIGtJiOsJqPXbbvm8QEATTPigJEqL7l8hGOTDED9VZDJV1FPHBuBzPPUIp8UNkkeX0s1cy+H5zE0jU3r12LCfSOQmpoaUDzP1VLK/1+5oStGlEistaRhYDLUX5Zl97cNP+HYgf346quvcPjwYdxxxx087xSU2P+c9RguFRQ0Cc/bsGEDXnl+AQ4d2C/jeRfOnQXDEfcQjfT0dKxYsQIWq1X8vTTWG7zyvPNnz+LAju34c/cuFBUVISsrC4MGDYLBYMCBPw+JfFmJ5znsdmzfuRNpqalo164dAJXnXQ7UIl8zwyBM1mW0WgSFhYuTxTzZdaU5I3/+8vMVT+GtKuSLhtnX9UbfUXkAgI1L3sWx/D0A0KQ5LYDzi93m4MQ8EQKnbSUZYQIRs1ssPndaiQ0mNCoaMWl8ka+y4KJPkzBJB5hMagvkIh/HcSgXyF9gdnhVu64S7EJhpyXz+NatWwe9Xo/evXsD4OX4aWlpWLx4sWy5P/74AzRN4/z58zCbjXhhzqMYcOtteO+999G9e3dkZmZi8uTJ+PTTT/H1119j1apVsvWjoqKQlJSELl26YPHixTCZTNiwYYP4ul6vR1JSkuwRHR0t20Z4eDiSkpKQkZGB/v3744MPPsCzzz6L+fPn4/jx4+JyW7duxQ033AC9Xo/k5GTMnTtXVJNxLIt77n8Azzz/Av45ezYy2rVH11598PGnn8JgMGDChAkIDw9HdnY21q9fL8sZMdXVer1eHzhwAIMGDUJ4eDgiIiLQs2dPNytCTFQUEhMSMKD/ADzz1FM4ceoU/vxjH0x1/I1pRHg4kpOTZechNFR+DY+NjUVSUhLatGmDvLw89OvXD/v27fN4XM888wwKCwuxceNG3HbbbeL5++mnn6DVavHPWY/yCwpFvmu6dkF6ejrW/8x/PqzdjtWrVyMjIwPXXnut2/bJZxcfF4uE+Hgkp6RAFxSM7LZtkZiQgM2bN4vLbtmyBXfddReysrKwc+dO8flft/2Kfr17idaR6Oho9OvXDytWrPD4vlSoaC64TtcFpEo+eZGvykXJBwDte/UFo9WisuAiSs+dgT/wpuSrZPnv1gjO3GQFhJM7t8NYXYUb6g8CAEokzTpiP45IcB6bLjhEtPvXNaDmUyryAZLhG0WFHtd1Kvl4zi0q+QI4k69caObGBmAsS4LazFVEa8jjuxyeZzIaRJ73zuL3AornsXY77n1gLP45+0nMmjUL0dHRyO7UGV+sWIm62loZz/vxx58AyIdk6ENCQDMMWLsdVpNJdny+8Ly42FikpqWhf//+mD9/Po4cOYJTp07BAaEREhaC1JSUJuF5a75ahUE33YjY8DAZz3vs0ZlgIMSi0BR69OiB9PR0fPvtt6Li8ZtvvvHK8xLi43mOl8wfM8Mw6NChA5ISE/H7rl1wCHxZieexdgd+37UbN/XrK25T5Xn+47KuIi+//DKuv/56hIeHIyEhAXfffbfsjwkAzGYzZsyYgdjYWISFhWHkyJEoKZHni1y4cAEjRoxASEgIEhISMHv2bJlVB+A//B49ekCv1yM7OxtLly69nENuNaiT5PFRFNWwkk8oygFA+YVzKDl98or2XykUDaOTU9F75P3odNMgcCyLiu8/Qoy1sklzWgBAy9BiB9k1r0Ukp0nJ0Gi1Iin2NZePBFqHRkUjKjEZNKOBzWIWyZ03ELtuQibfMQhkC4fB6oBFyOsKRPKndniVIdp1WzCnZdu2bejZs6f4M03TGDNmDJYtWyZb7ssvv0S/fv3Qpk0bbNqwAdVVlfj7Q4+45bXccccdyMnJcevOShEczMcHWH3Ma/OGRx99FBzHYc2aNQCAgoICDB8+HNdffz0OHDiAxYsXY8mSJXjxxRcBONVqq779FvHx8fh1y2ZMHPcg/jlnLkaNGoW+ffti3759GDJkCB588EHUSbL4HHa7V2VKXl4e0tLSsGfPHuTn52Pu3LnQauXBy3ZxsIUWUULjw2azwVzFXxPJUBNfsXfvXuTn56NXr16Kr7MsixUrViAvLw9JSfIiQXBwMB5++GFs3PAzaqqqACGQmaJoTJw4ESu/WS2+748//hgTJkzweizOTD5GzKPp27sXNkusNps3b8bAgQMxYMAAsfhnMpmwN3+frMgHADfccAO2bdvm1/lQoaKx4bA73RohPhT5akqcvIdAHxKKdj1uAAC/HRzelHxldv76EmT3rpi7EtQLjexEYwF0rEXG88TJukIeH4HIgysus8iXQoZvXIIn1AuDPYiSLzjAM/k4jkOFIfCVfK6W7r86ApXnbQhgnkfcGl98+SXi4uKwe/duTH/oIcx9bgH+PnmyjOdNe2QmjCaTyyRcWjKtW3498YXnAc6iofQ8ODie31Ec59ffiD88Lz6Ov/baLBY47DaR5/3888+orSoX3x8ATJw4EZ988omoclz66adeeR4rybOWov9NN2H7zl2wC5E2Sjyvvr4Wfxw4gP433SRbV+V5/uGyinxbt27FjBkzsHPnTmzYsAE2mw1DhgyBQZhcBQCPPfYY/ve//+Grr77C1q1bUVhYiHvvvVd83eFwYMSIEbBarfj999/x6aefYunSpZg/f764zNmzZzFixAgMGjQI+/fvx6xZszB58mT89NNPV/CWWxbi0A1BwddQkY/YDyLiEwDwar4rAVHyxaSkgaIo3PrQP5Ca2xmUzYzbS9ahTWTTT+kiWRwlLh08MnSDkN3wuHgAvufyiZl8UTFgNBpRledLLl9tGb+PhCy+yGeqDVwlX7lQHAvRMQjRBd5UImlWy1+F/HEcB5vZ7PVhNhnhsJgBu7XBZf15+HOOz58/j5QU+c1jXl4etm/fjgsX+L8zKYEAgJMn+cZEVnYHOBRUtbm5uThx4oTi/oxGI+bNmweGYTBgwADx+bVr1yIsLEz2eOmllxo8/piYGFmY9Lvvvov09HS8/fbbyM3Nxd13343nn38eixYtAsuyYiBz546dMG/ePHTokIt/THsIer0ecXFxmDJlCtq3b4/58+ejoqICBw/y6hVC2LxdRy5cuIDBgwcjNzcX7du3x6hRo9CtWzfZMqzQ6SytqMSrr76K1NRUdOrcBeA40ByLf//fs27nwZUA9e3bF2FhYdDpdLj++usxevRojBs3TvGYysrKUF1djY4dOyq+3rFjR3AchwvnzoBhnV3esWPHYtfevbhYUIBzZ85g+/btGDt2rOI2yGeX1i4b7a7pjrHjJ4CiKGi0OvTr1Qu/79gBu92Ouro6/PHHHxgwYAD69++PLVu2AAB27NgBi8WCvr17y4h2SkoKzp8/7/F8q1DRHCCOAprRiMMhAOUin8NuE7lHlETJBwC5Nw0EABzfvtUnNwLAf4+Q2JNIBSXfRZMQfm4z+TUkxx+QRjbNscgwXpRN2BUn6wp8loAU3kiB0BPI4I0QYbIugXPCbsNKvvCrJJPPYHXAbAvcZi7heWYbizpL802rb0n4xPOMJp7n2QKL5xEOx/M89321Vp5nt9vF62u3btdg3rx5aN++PeY8ORt6vR4x0dEiz3v22WdRWVWFo8eOu03ClSqDpddrX3gewHPGoqIiked16NABVuE0Lvz3fxAeHt4kPE/6PWAx8s0fwvMunRVU5ILqe+zYsfjtt99QUFSEiwUF2LFzp1eel5CSinbXdEd6Nv++CQYOHIA9+/bBYjJ65Hk7d+6CxWqV/T4AKs/zF5dVAfjxxx9lPy9duhQJCQnIz89H//79UVNTgyVLlmDZsmW4+eabAfDe+44dO2Lnzp3o3bs3fv75Zxw5cgQbN25EYmIiunfvjv/7v//DnDlzsGDBAuh0Orz33nvIysrCokWLAPC/eL/99htef/11DB069ArfesvAWeSLkf2rRG4cdjtqSnnC1u9vD2L924twdPtWDBg3Cbog/4djcBwnkiDS+dRotbjriWfw5kMTEWmvQ7xd2TbcmEiI0ONIEVDmUcnHf7mEx8ah+NQJ35V8YpGPJ9OxaRmouHQBFZcuIOva67yuW1vB7yMxi894MhsNYB0Ot2lHgQDS3Q1E4gc4O7wWO4tasx2RwU1feG5p2C0WvPX3+1pk3//49Gtog4J8WtZkMiHIZdnu3bujY8eOWLZsGebOnYutW7eitLRU9qUOAOA4j5PXdDr57+qYMWPAMAxMJhPi4+OxZMkSXHPNNeLrgwYNcrOOxMTEwBdwHCda1Y4ePYo+ffrIrGv9+vVDfX09Ll26hPjoKABA506dAPDBzAzDIDoqCl26dBHXSUzklSklJSVA504Ii45BTWkJLEYDHHa7THFG8Pjjj2Py5Mn4/PPPMXjwYIwaNUrMHiHo3PN6cBwHk8mEbt264ZtvvkF8egZKzp8DADz8yEzMmD5Ntk5qaqrs55UrV6Jjx46w2Ww4dOgQZs6ciejoaDG42dM58gaKosBwZMItjfj4eAwZPBirvlkNbVAQRowYgbi4OMV1yWdXUXgJrM2OlKy2AACNToe+vXrBYDBgz549qKqqQk5ODuLj4zFgwABMmDABZrMZW7ZsQWZGBtJSUmTnNTg4GEZj0ymUVKjwBc48vihxOATANx8Bp+MA4LOAOY6FRq8XeQtBVvfroNHrUV9ViYpLFxCXkdnwvmuqYTObAIpCZIJ7ke9sPRAJCjQ4GGurxYJXY0L6/rKM52WxG0TJF+FybGJszRXadaXxNq4QXTSx/L7ETL4AteuSPL5gbWA2c4N1DML1GtRZ7CirsyAiSOV5TQmV5ynzvAvnzyEEACiga1fnvrU6PaKjopDbvr34XEI8Lzwpr6iQNRgBQBsUBFrDgLU7YLOYxQgCbzyPFAN73NgfAF/sJDxPp9PBZuStv9OnTMZDMx6BVnL+GovnSSfcWgwGWQOFgVCsFL7H4uPjMWLECKz46itYTSYMvXWwV57374UvwlxXh+CICCQKEVr8azfDaDRib34+EBSiyPO2/fYb2qSnuw1+UXmef2gU03+NYFEif3z5+fmw2WwYPHiwuExubi4yMjKwY8cOAHw3vmvXruLNEQAMHToUtbW1Yqjijh07ZNsgy5BtBCJI9h5R8JF/jdXVbuOka0pLwDoc0Oj16NhvAKKSkmEzm3Bix2+XtW9jTTUsRgNAUTIrR3B4BKq1/B92FJo+HyORKPlcJuySDjTJkokgSr6Khot8NquFf28AQqNJkU8YvlHg2cIBgO+eCfaaBOGGExwXsORPzGkJwMm6ABCkZRAexJNWNZevdSEuLg5VVVVuz+fl5YlWjmXLlmHYsGGIFW6m2gsk6cyp44od3qNHjyInJ0f23Ouvv479+/ejuLgYxcXF+Pvf/y57PTQ0FNnZ2bKHL+SvoqICZWVlyMrK8un9ki4nIaeMUPSnKApaSYGJkEeHYE/Qh4ZBqw8Cx3EelSILFizA4cOHMWLECPzyyy/o1KkTvv32W9ky3y1fhl/W/g9VlZXYv38/evXqBZqmwdL8vuNiYtzOA7F7EKSnpyM7OxsdO3bEqFGjMGvWLCxatEg2yIIgPj4eUVFROHr0qOIxHz16FBRFITOrrbPIJxDAcQ+OxcrV3+LL5SswceJET6cUoaGhaNeuHTLT0pCV2Qap6fx1mtHpkJXZBikpydi8eTM2b94sdnFTUlKQnp6O33//HZs3b0Y/ISuIlnTTKysrES+QcBUqWgpKeXyARMlX47x+OjlPsltGnkarRUoOr6i9dNS3oHGyvfDYOGgULGEF1WaYGP76YBQUh40Jh90mFuIAoI3pPEqqnQ4fksnnatcNF74rGopWaciuW1teBptVmTPUe1DyWQJ08EYg5/ERiNEstSrPa024Up5ndwQOz2MdZLgEJStC0gwjToglTU9R9UZRoF2iUiiKEsU3VrMzl88bzyP3/GtWLseBAwdQW1sr8jwAsAqxSzHR0WibmdkkPE+q5LOajGBZVuR5bduQwpzzu2nixIlYtmIlVn37HR742988ntfQ0FBktWmDrMw2aN++PZKTnUr1Drm5SElKwm+/78Avv/yiyPO2bf8d/fr0dmuQqzzPP1xx+4dlWcyaNQv9+vUTlQ3FxcXQ6XSIioqSLZuYmIji4mJxGWmBj7xOXvO2TG1tLUwmk9svOQBYLBZYLM4vjNpWZrusl2TyAUBIZCQomgbHsjDUVMk6qyRfJDo5FRRNo8ugIfht+af4c/MGdBl0q9/7JtbfyPgEGQE0Wu2oo4MRD0BraXrrQmIE/8UutevarBaxmOdU8vGWDl+UfKR7rtHqoA/hcwVj0/iJPxUF3u26ZPv6kFAEh0dAHxIKi9EAU12tmy0kECBO1g1g8pcQrked2Y7SOjOyE8Ja+nCaHBq9Hv/49GuvyxwrroXdwaJtfFijdu41et+Lwddeey2++OILt+cfeOABzJs3D/n5+fj666/x3nvvia8NHToUUdEx+OyDdzB88EDZet9//z1OnjyJN954Q/Z8UlISsrOz/XofvuDNN98ETdO4++67AfDq8G+++UbW9d2+fTvCw8ORlpYm3hiSQhZF06K6l/VgoWM0GtA0jeCICNjKzPx1JDJKMeg+JycHOTk5eOyxxzBmzBh88sknuOeee8TXM9LTEBUVhUiX71KH0J+jOd9sfLLjYxjY7XZYrVa3bj1N0xg9ejS+/PJLvPDCC7JcPpPJhHfffRdDhw5FbGwsGAN/w07e17ChQzHz0UdBUXSDSnuOZUXiTM6nRstfr27s3QdbtmxBVVUVZs+eLa7Tv39/rF+/Hrt378aYV17m34vGqbQ+dOiQYgC0ChXNCaXJuoCzyGcxGGC3WqHR6ZwRJQrWWgBI79gFF/7cj0tHD6H70BEN7ptsTzqpV4qyOguMTDBCHUZZMa6xYBAKAzSjAafVIdhsRPn5UwC6wWI0ig0PV7uuGFvTkF1XEBSERMp5WXB4BIJCw2A21KO6uAjxLqpHu9UqDlMjQ92CSCafITDtukTJFxuAeXwE8eF6nCk3oKz+r1Hk84XnnSqtg9nmQEZsaKOqG5uT5w0ZJLdYtmael5KUiNqyUkgLWYB80i7rcIDRaOAQMuQ8Obx0QSEw19fDajIDksu/J55HCmxZWVlop3AebA4nvyP5dr7CV573yMTxSIiPF1WINZUVTp4XIcRNSLjrsGHDYLXZAJbFIJe8PFcoTS0GeB7dr28f/L5rNwwmE56cM0d8rX///li3bh3+OLAf48bcLw75IFB5nn+4YiXfjBkzcOjQoVYz7eTll19GZGSk+EhPT294pWaEa5GPphmEEsuui1WhstA5JAMAOg+4BRRNo/D4EVRcuuj3vitJ0TAlTfZ8eZ0VBoaXFtvra9zWa2wkRBAln6QYK3R4dcEhCA6PACBR8glDMbyhvspJrMlFPDZVmLB76aJX+xkZukEyAMn+zXWBTf4CMYyZIP4vNmGXoihog4I8PjR6PaDRg9EHISQkxOuy/j78mbI4dOhQHD582K3Lm5mZib59+2LSpElwOBy48847xddCQ0PxymtvYcvP6zDrkYdx8OBBnDt3DkuWLMH48eMxZcoUDB8+3K/zZbFYxO4veZSXy1UgdXV1KC4uxsWLF/Hrr79i6tSpePHFF7Fw4UKRWD788MO4ePEiZs6ciWPHjmHNmjV47rnn8Pjjj4OmaVGZJz1HJETYU04WIxSrgkLDQNEU7FY+W0cKk8mERx55BFu2bMH58+exfft27NmzRzELT6PVyfbPcRzsAiGtr693Ow+uja2KigoUFxfj0qVLWL9+Pd58800MGjQIERERisf/0ksvISkpCbfeeivWr18vnr+hQ4fCZrPhnXfegZZiQYGTnRudXo9ff/wR2zduEBWPnkDIH0XTYkdcI3TR+/S6Hr/99hv2798vy2MZMGAA3n//fVitVnHoBgmEBviw8CFDhnjdrwoVTY16yQAwKfShoaLFi0SLiEo+hSEZAJDWkW+cXzp6yKdMLWcen3uRz2i1w2B1wChwPUMTFPmcg+ViEJHdlX/y4hEAQK1g1Q0KjxCtbASEDzes5BMiWSLl55aiKK+WXcKtNTq9GJBP8hJNAarkqzAIzdzQwG3mOpV8f40Juw3xPG1QEKAlPC844Hjef974L7b8vA7//Efg8DxyXXU9PxRFiWU/UmBz2Pm/OddBEgTaYP7e1mYxiTEr3ngeGfih0SgXc+0sBw4U6g0GFBUWNj7PS0zE3/4+Ab/8ug3l1bXYsXsPRtxxJ2w2G9568w1xWVZSAGUYBgf/+ANbf1wPwPt3kqfBGwDQ/8YbsTs/HwcOHnTjeR988AGsVhv69e7ltq7K8/zDFRX5HnnkEaxduxabN29GWpqzcJSUlASr1YpqFztASUmJqAxISkpym7ZLfm5omYiICEUVHwA89dRTqKmpER8XL/pfDGtKkE4lITWANJdPnodHyEqMYEUIi45BW2Hi2p+b/R/AQYqGJKSYoKzeAgPDq99cJ781JuqrKnFgwzrEhfA3gNLpqVWSybrkYuvP4A3SPQ+VjFePEhSQFqNBlhPjCr6L4ywqBoUL5K+udalAfQUhf4Fs45AO31BBvuz5L1SmBaeude3aFT169MCqVavcXsvLy8OBAwdwzz33uF2f77pnJD5a+T0uXbyAm266CVlZWZg8eTLmzp2LDz74wO/j+PHHH5GcnCx73HjjjbJl5s+fj+TkZGRnZ+PBBx9ETU0NNm3ahDmSrmFqairWrVuH3bt3o1u3bpg2bRomTZqEefPmAXBOgJVmaxH1GMvK4xUINDqesLVt1w6vv8t3ul2vJQzDoKKiAuPGjUNOTg5Gjx6N2267Dc8//7zH7RE4WE5U8r30r3+5nYcnn3xStvzgwYORnJyMzMxMTJ06FcOHD8fKlSsVjx0AYmNjsXPnTgwcOBBTp05Bu3btMHr0aLRr1w579uxB27ZtoSFZLRQtdnlpjRbh4WEICQ5qsCBByB8jIXA0w4CmafTr1QsmkwnZ2dkyJf+AAQNQV1eHnPbtkZiQIOvw7tixAzU1NbjvvpbJO1KhgkAsREXJbWUURbkN32hIyZeUnQNGo4Ghukpc1huc23Mv8pXX8bzAqgkRjrO6we35CwPht9GxSOt+PX8sZXzYvmjVjU90Wy9McLB4y+TjOE4cvBGs4LAgg9aIY0WKOnGybqzIL0kmn6W+3ufBJq0JTiWfyvOuFnAcB7ug3tIwjZKmdVm4XJ53z70Cz7t0MWB4HqvQyBUhPEeakqKST+IgyMzMxIIFCwDwDVmaYcCxHGwWS4M8TyyCKUQr8L8LPI/6zxtvol1ux0bneVu3bEa/3r3w5Lxn0f36G/DQPx5Fm7RU7N69G23SeSecg2LcSnnRMTEIDw8Da7d75XqelHwAz+fMZjPaZmUp8rx2bbOQnJwss0WrPM9/XJbni+M4zJw5E99++y22bNni5nvv2bMntFotNm3ahJEjRwIAjh8/jgsXLqBPnz4AgD59+mDhwoUoLS1FQgIv3d+wYQMiIiLQSQg579OnD9atWyfb9oYNG8RtKEGv10Pvhyy5OcFxnEhiwmVFPuXQ4SqFolzXm4fg9N6dOLJ1E24aM85two83kMm6rko+3sIhdHe9FMOuFDu+WoaDm35E26EjASTIunc1JfKhG4Cz6FZfXQWH3eb1vdZXC91zSYdXo9UiKikFVYWXUHHpoqywKgWxCZMJxs4Ob2AW+coJ+QvQTD6At+sC8kLwXxnky15D06D96Mg2BebPn4/Zs2djypQpsi/g6dOnY/r06YrraBgKPXr1xaCBA9AmNhRmsxl33XUXli5digkTJsgyNhoqEC1duhRLly71ugyZquYLBgwYgN27dyu+5nDYsXrZF2K+J8B3Jfds3Ywwl2yYqqICmA0GMFodjEYjSkpKcMutfKyC2VCHcEecSHZ0Oh2WL1/u8ZgGDhyI6pIimOrqRGUggY3lwFI09mzdDG1QkKhYdkVmZqZP6p8FCxaIJJUgLi4OLy14Ds/M+gdCIqPEazEByeN76/XXkUgy9YT3xnEcWNYBhtHgu+++k61HPjeTYNuTkmWKosDodEhPS4OprlbMzCJo06YNOI6DoboKdRXlsu+DN954A7Nnz/bY/FNxdaE5Y1ksRiPyf/gWGZ27Ia1TlwaXJ64CVyUfea62rBQGga84M/mUlXwanQ5J2R1QcOwwLh09LKrVPKFGVAa6F/nK6gW+FRIG1DmLkb7i8NZNyF+3BiP+MdvjNUfqVOlw3XU4+AWNcEsVKgoKRCWfq1UXcPJhY22NR65nNtSLN42umXyAk9cqKvkEhWCYJA6HKPo4joXVbBJjXgIF5WIsSwDzvIi/lmOjIfDNXB4aOvB4HkPzPO+m/v3RLj6sRXgex3HCwDP5dcQTzyON3PVr/ycKbggO7N4lDk8DALvNjqJTJ8TJ5YTnDRw4EADJ5QuC2WCAzWxEaFSMV57X94YbUHTqBCIUhleQxv7W7bsQajcgODzCLcsU8MzzzIZ61FdVwmY2QxsUpMjzYqKi8OL8Z/Hvl19GdHIySs+dBceyiElMhMPGX18cFIPX3/kAKVFObkV4G+F6SjyP4ziUnDnFL69Q5GvXLhtFp064XXfbtGkDs6EeVUWFblZdlef5j8tqFcyYMQNffPEFli1bhvDwcFE+ajLxYZORkZGYNGkSHn/8cWzevBn5+fmYMGEC+vTpg95CYPaQIUPQqVMnPPjggzhw4AB++uknzJs3DzNmzBCLdNOmTcOZM2fw5JNP4tixY3j33XexatUqPPbYY4309psXZkO92AmQdnnFPBI3u657US6re0+ERsfAVFeL0/nKN6aeQCbrEmUgQVm9BQahu+uqJmxMkPdT8Sd/3KV1FrBCEL+o5JN0tIMjInl7i6Q46glOJZ/8Ih2byp87b7l8RMkXHiu365paWZ6jr6i4igKZVfLHw86S7m7LEj8AGDFiBKZOnYqCAs+TDF1BCCsZvBEUFIQ1a9Zg3Lhx+PXXX5vkOK8UHMeBtbvbDUgQMCGHBHbh2q7RarF582bcfPPNGHzrEGh0OnCs/4N8pNuTPe9gwQpf3a7DmhoThOSZDfVuJJIWVIwcLSnS0bRIyli79/wYpfMKOHP57Far5+MS1iWfg9VqRdeuXQOWF6jwH80Zy7Lj62XY8fVy/PrlJz4VzZVcBQROJV81OJZFTSkpyikr+QC5ZbchVJFmqYKSj3yXakIjxWPwFUWnjuPn9/+LsnNncHLndo/L1UmKfKnxMSgM4o/j8M7fRSVfhMKNanB4BP/3zHFirp8riPJQHxKqOFSEFEArFYp8dQrNdY1OJ+aUeRqO1JrhdGwEbpEvPkxt5kohqvho2i97bVPginieo+V4ntVkRHVxEaqKCn26Xjstpe6FKDF/WVTy8X9zxF5LeB4p8gGAlgzfMDVsQSf1ANdJvYCzsQ+aHIPvmXx2qxU1pcWwWyxer21OLsWAomjoQ/g6gMVoEI+NpWi3gXkUJcmm9sD1pNxU6dyS90z2o3hcEn6o8rzLw2UV+RYvXoyamhoMHDhQJh+VSkNff/113H777Rg5ciT69++PpKQkrF69WnydYRisXbsWDMOgT58+GDt2LMaNG4cXXnhBXCYrKws//PADNmzYgG7dumHRokX46KOPGgz1bq0ghaqg8Agxfwhw2nWlKjqL0SCSGmn3lmYYdBnITxz+c9NPPu/bYbeLhDLatchX1zx2XaKYqym8iBhbFRwsJxIV0WYi6UBTFCUqSBoavuHsnkfJnheHb1zyUuQTMvmIki+IZPIFIPEDnEq+q6HDW1r318hqaQjkS7alu7sEs2bN8uvGmhGO2y4hC0FBQZg7d66o9m5tEEkVJScppJDlkJAujuMkhE2HESNG4IcffgBFUZfVNOC3ZxW3J4XdwSv5ADRol7gSEKLF2u1umYI0K7xGy4t0pPDmaKjI58HGQb4X7TZvRT6bbF86nQ7z5s1Tu7t/ITRnLMv1d46ERq9H0anjOLV3Z4PLK7kKCKR23brKCjhsNtCMRmwwKiGtY2cADU/YNRvqYRZiAZTsv6TIFyRYXX2165oN9Vj7xr/F62FNWYnHZUUlX3QMdBoapVHtAACn9+0R14tMcD82iqYRKjha6jw0dE3i0I0oxdfjBHtZ2dkzsJqMstdI1h8ZukFA1MLmAMzlK68jPC9wm7mqkk+OwOd5PC9pSZ5HJttKh+14A8nFc53iCjgVa6zDDpZlRd5CClSE50mhE3iIzWzyys04jhO5jFImH2nsU7S80NgQWJZFdUkROJZMBHYvoonLijyMf+9EVWcxONWLDopxK/IBUq6nfFxSjqdUsJZyPVe+yLo0cgGV510uLqvIx3Gc4mP8+PHiMkFBQXjnnXdQWVkJg8GA1atXyyb1Abwsc926dTAajSgrK8Orr74Kjcsf2sCBA/HHH3/AYrHg9OnTsn0EGkSrrovaTAwdlpAbYtUNjYoWq+sEnYUi3/k/98NiNPi075rSYrAOB7T6INEeTCC16xqrqz1mTV0JOJZFXYXz/XW1ngfgLOJUCx3oaBfbCiG/DeXyecrBIbYSb4NKSAExIk6w65Kb8kAdvHEVZPLFh6lZLVKQL9mWtupeLlyVfIEAQl4YRqM4eEPawXTYbeLkNleySDI+bRazYtdSCSzrACt09V27vHaWBUs57RJNlSclJV5uKkTWSQCl8L3I5+wgSyESP5+UfI03eVBFYEGv1yMiIkL2aCqERkWj5/C7AQC/Lf/M680Wx3Giks/V+sVvS2joVleiWnAvRCYkeJzWCAApObmgaBq1ZSViQ1IJxKobEhnlNtgCcH6XhgmNUJJv5w0cx+Hn999CbVmJOOSGKPKUQBrVhNOaknMBAJVnjqHs/FkAULScSdepr1QevkEGhbhO1iWISU1HdHIq7DYrTu3dJXuNbDM8xqXIJ1h2A7HIV2EI/FgWcfCG2swFAIjirVZS5PMXxGniYLkmaz42BLskxsFQVQm2AX7kTcnHME7XhnSyrrfrtUanB0XTYFm2QR5DOKOrLRVwKvlc1YQNoa6iTLZfuxcu5lpMI0U+u9UiFks9FflE14YHhaG3PD6yT60w9deVXxKOp3ReVPiHlkv2/AvCdbIugZJdl1gOXFV3ABCdlILo5BRwLIuLRxq2cADySb2uVfXyeguMTDAAChzHNolN1VBTLbsYtK3nvfqltRY47HbRMuuaJRPus5JPIJcuxDpGouRT+tJhHQ7xvEeI03UDd/CG3cGiyigU+QKY/DmVfGqRDwAcwu8uE6DkT9rhbSny5y9E8qdxVavxpEVayJKq+FyvrwzjJDOEODUEh9WpVpPm4QCAzSHk9hA1nx82Dl/BSbrWAGBxtewK+7RDucjHNlDMJAVUT3Zdh83m8feEtZPwa5UAqmgeXH/nvQgKC0dlwUUc/nWTx+XMhnrxuqCkOJMq+aq9WGul0AWHIDGLV8QVeFHzNbS9MiHGI1LIEvVFyXfg53U4uet30IwGAx6cBMB7kc91sFxEQhIqtNEAyzoHnClk8gFOK62naBZjLX+8npR8FEUht19/AMDx3+XWQNJgdlfyCUU+Q+A1dK+GWBYyeKPKaIPVHnjDTxobpJgSuDyPP24OXIs0dDmOH3gB8NcDh90Ok5dmBh/JosxF+OcErudweLXWSkFy+QDvfE+6PSWlm00oToqcyuFokDub6uvE+3dyP+uNSzlcOC7NMNAJdmNyfA7QMmUmAaPQ7JaCiIW8FUSdSmr59dfhcFfyqbg8qEW+ZoTHIp+grJPadcmQjJhk+ZAMgowu3QEAF/7c79O+nUM33IuGZXUWcBQNTRjfDW+KXD5i1Q0KDQPNMAgzliHKWoWSWjNqy0vBsSw0Or1bpl6EjxN2ic3YNew6JiUVoCiY6+sUL/b1lRXgWBaMRiOuGxRG7LqBV+SrMtrAcfxQqOiQwFW6kKyWaqMNFg9y8L8S2AAnf0TJx3Ec2EAp8inkggASJZ+EdJHOqVJWFABRWWM1GhVfdwWxqzI69xs4QrgoQkCb4O/DIZk4R9E0HHY7bBZebcE6HKJ60O5CIWhBXeerks+VWNMaDSialtmfZetJFY4qAVTRTNCHhKLX3aMAAL9/tcyjQoOo+IJCw2SRLAQkp89Q5SzyRTZQ5AOAVDGXz0uRj+QaKwzdAJxKvtg4QWVXW+vVtVFy9jS2fPYhAKB/3gTk9OkHgOdySqoSjuOcmXwCj0uM0ONsSKZsOaXpuoCyo0UKUpQMiYjyeMwd+vJFvnMH9smatE4ln5x7B4Uq32S2djhYDpXGwC/yRQVrRW5AYmb+yiDcKEBpHmiKAkO1nGuDtdv5axPldIEZqis9quAayo1zcj07HHaBk/ngICC5fDaTlyKfGDuivD1x2J7GN9eG3WoVGylh0TFi7BTHsh7XU8pG1ofKB2E0pOTzxPWcxVMvRT5BSW0zm8UMak/HpeLyoBb5mhGkyxkarazksxgNYvaRU3mnPHWtTdfuAHjLri8g23MdugFIslqEDimZ/NaYIJko0alpyBCOPdt4BiW1Fic5TUxy62iISr4Kz0U+lnWIBNC1yKfVB4n2EKVcPmJ/CY+NByUoZgLZrkssHDEhOmiYwP3zjgrRQiccP5ki91eGaOMIULsuTVPisSt1BVsjnJYBOUmRZowQMiJ2ZXXKhE0v5IhYTEaflIwOD0M3AGc4NyXaOBpfySe1xAaRnBbB0maXBDLbXd4Ko5BXqARPVg6KorwO3xA/E4b2Sh5VqGhsdB96O8Jj41FfUY79P61VXIY0SEMUJusCzpw+Q00Vaop9U/IBzuEbF70M32hYycdzg8SEWIDy7tqwmoxY+8YrcNjtaHddL/QYfifComLAaLVC9Io7H7MYDaJVjnDaxIggWZEvNDpGsfgJAOGCyo5MwnWFsQG7LsDHs8RntgXrcODk7t8B8DfTxOob7knJF2B23SqjFeRrJCYkcIt8NE1JLLtqkS/QlXwAwDAtx/NsVmG4kFaP4Ag++551sB6z5qVWXSU1nTSTz2GzC9tuuMhH1HBWL7l8DSkDxSIfw4BmvA9a41gW1aXF4FgWuuBghEbHgKadHEkpl4/jOGfGoITjSqfdUhTFD97g3B04DXE9T41c122QDENpo8V1uJqKy0fgVgFaCexWq8/2s3qFCV8AoA8JESv/pItZpTBZV4r0ztcAFIXKgouo85BhIkWVaP+Vb4/jOJH8hYsDQPwbvsGyjgbVf3XlQic1Nh45vfiOcLbhDErrzIpDNwgiYhOE9T0X+Uy1tXyngqIUrRxiLl/BJbfXiA2YFBOBwLbrXg0WDoD/chHJX62a1+JU8rXwgVwBXCevtXZ4IikURUlsHIJtlUxd0yr/3Wn1QTxhcji85rQQeNueM6vFqSj0B3zgs4/TbzUa6EVLW71MYafU4XVm8nm263Kc0wrsWkAFAI1QKFUavuHs8AauSllFYEKj06HvqAcAALu++0oxD9mZx+ehyCdwLGN1Naq88B5XpOZ2AsDzQk83rA0p+cighoTIEAQLNilPlt3tK79AdXERwmPjMXT6LFHRS3KLlSy7xImiDw2FVs/b1RLC9SjRJ8Cu45XMnqy6gCS2pqoBJZ/CQBMpcgU137HtvwrHVQVwHBiNRmzgEoh2MT8nn7c0CM+LDtEGdDMX4H9HADV/GXAq+ZgAbeYC/GRgoGWUfKTJoNXrQVGUeE0x1lQrch4nD1EuJhGOxbGcWEBsyK4r3T8rsfm6wlsjF3AO3tAylExRqARDdRXsFgtohkFkQqJYsPQ2wVbqRJFyXEarFY+JnBfegSNfXymb2nX7/HLem7Gu12CpU0SJH6rwD4H97dDCOLlnBz55fBpO7d7h0/L1lfJQYimkuXwcy6JKIGxKyjuA70Amtc0GAFz480CD+yZFvphk+fZqzXYxCyMq1t023BAcdhu+Wfgs3p82DsWnT3pcrq6CKObi0O66XgBFI95ajsqiQgk5dVctSjP5PBVTCekNiYhUvKB4m7Bb5zJ0A3Aq+cz1dU0Wat9UIJaHQM7jI4hTyZ+IQB+8AShP2G1OOOx2VBcXweKjZVYcvKE4dc0ZyAzIM/mUQNG02LG0erFwiPv20uV1ZrUIXeYGCnZScByHmpJilJ0/6/U8SDupuuAQiWXXIk79dVAMWI4TC9CA/Lx4tojw54yiKNC0UpGvYSUfo1U7vCqaH53634yY1HSY6+uw5/vVbq/XEy7ioRBFVGiswy7yEV+UfMFh4YjLyAQAFBxTtux6U/JxHCd+j8aH68VmqMFDkY8oBgc8OFEsCALOoRlKRT6nVdfJbxMigsBRNMqj+UxBT1ZdAAgThmJIB7RJYRSn63pW8gFAhz438e/hyJ+or6p0TtaNiRXdGgTOwRuB5dqoIDwvLPB5njp8wwmR5wWwkk8j8rzmv3eySYp8AK9K0wYFgeM4xftakU94KETRNC1eM0gB0Re7LkXTDeYw2xtQ8tmIko+mZNmASiD7CIuJlR0f4yU+RZo5LVUxUhQlqvmkeYEOl8+zoSFrPhf5QsNAURTsFgvsVqtzPZpW5Icq/INa5LsClJ45hdqyUmz5/COxyu8NrqHEUoSJKroK1FWWw261gGY0iExIcluWgNheG8rlMxvqxS6oq/2XFIXCgzSIFIp89R46xUrYvPRDXDh0EIBn8gk4lXwRsXEIiYhEWBY/dY0+f1BCTt3fa3gcT/xsZhMsBuVJwmIen4dAZlLkI9PdpCAZBlIlnzTLwNeCQGvB1aLkA5wdXtXGEfiDNwCIioOWKvKZ6mphNtSLk8YbgqfBG4Azp8/hsINlHSLR8WblEHP5TN6vKVK1nKuSj+WcgdYaQuD8UPLVV1WKHVNvodDSqWs0TYukz2KoF1V6ZLKuQ9J8oWmn7cWTjcMhIX9KFhlGtOu6/92LxU/VxqGiBUAzDG4cMw4AkL/uOzcHg8hFFCbrAoL9XeAXfHYU5XHarCvSOnYGoJzLZ7NaRKeIkpKv1myHVbD5x4XpEUom7CoU+TiOQ3URrzIkhUUCcqy1Ze5FPqXM6cQI/kZ3f3RPtLnmWlw77HaP7484XAxVFYoNXaeSL8rjNsgxJufkAhyHEzu2iU6XMJfJuoDn4PfWjnIDz/PirgKeFy8M31CbuRLHhtrMvSzYrHyhWCMU+SiKEidqG+tq3BqHzkKUF0sp48zEA3xT8gFOy65SLh/vpmggk08oqmkk0SSeeKvIF12iEEgzVEnJ563AGRIZBX1ICEIjo5wOHJfPk6jsOJZVnGDsa5GPZhiRG5vr69TJuo0Mtch3BbjhrlEIi41DbVkp9v7PvasrhcNuF0mKNyVfXWWFmJ8XlZjk9Q9EzOU7dMCrZbhK2F5YdIz4x0QgdnfD9AiNchYafcGBDetxYMM6534ERZ4SSDeVFNPSe/QGAESVHJVk8rkr+bQ6PYIj+M4tyc9zRUPEOrUDb3UpPH7UzdpMthkR7yzyabRa0T5tCrDhG6RoG3cVdXhV8uckf62hw1tRUYGEhAScO3fOr/WcZKFl1LEk75R1NBwvAEhJkDcln10kUDTDeL1ei0U+LzktgHMaGkVRbkSHWHX57DrvFg5XmOvrZN1sh4IdVnzNZYKtqHgx1IsdaI4WCKSE/FEU5bSIeOzwes9q0Qbx1ma71epW6JNmBSqhvLwcCQkJuHTJPZpBhYrGQPZ1vZGckwu7xYLfln8qe438fblmA0sRJnktPCbOY0adK9I6dgUAXFLI5aspKQbAK1eCJMo7AvIdGh6kQZCWEZWGRoWGrqG6CjaLGRRFuzVeI+I9K/nIe5cp+YTv8LO2ENz71AtIyeno8f2RoSQOu10xKkWcrutl8AZBbt8BAIBjv/8qZvy55vEBgZvJR6zXV5eST+V5YvbyVcHzmrfI57DbRZeARuf8u9AFB/NNSg6oqyyXcS9pJp8nSDkYRfueBawlzg0Fvie1pCq5ElhW0syVKPmUuB7LshKHg5wXOZV8ynZdwEMTW6tFdHIq9CGhYtHWrchHM6LKUclN4st0XQLpddhZ/PRc5FN5nu9Qi3xXAG1QEAbkTQAA7P7ua49FKMA5zIJmNDL7A4E0j8TbJFwpUnI6QqPVwVBViUqFvDmCSi/5foT8xYXrZZPfGsKlo4fwyyfvAQASsngrBsnWUwIJaiYTjzr37QcWFGJMpagq8p5NI07Y9TB8w0mslYt8UUnJSM3tDI5jceTXzbLXahXsuoAzl88cYMM3RCVfaOB3eFUlnxOOVpTVsnDhQtx1113IzMz0a719e3ZhxrhRaJ+ejKCgIHTt2hWvvfaamxKNoijxERkZiX79+uGXX34RXx8/frxsGfIYNmyYuExmZqb4fHBwMDIzMzF+8hT8toOPVjDWVisqxQhYyUQypVwQRhLIbLcqq+5codHpQDMMOJYVC45KsNts+H3nLiS1a8/bRSgKiYmJGDlyJE6eOsVvi6bQsXMXJGfnIDY1XXYeXnnlFQDAuXPnQFEU9u/fD5vFghpBfaPV63HvA2Mx95l5svP1xhtviD8T0vjSv/6F7t27QxcSAoqm8MhjjyMuLQNPPjsfYORFvhkzZoCiKMx8YjZ/biTEb8eOHWAYBiNGjHDL4yPHmZCQgLq6OjCMBroQviDao2dPLFiwQNzOiLvvQXJ2DsKiY2Tvedq0aQCAuLg4jBs3Ds8995zXz0KFissFRVHonzcBoCgc3roJ+3/6QXzNWCNk8nkp8kmHcviSx0dAlHxlF865FaWkeXxK6lipVReAV7suiXaJSEhwK6YTZ4lXu66kiU32Z5dMg/UERqMVj6vOZfiGzWoRYw6ICtEbOvS5ERRFo+jkcVw6dsTtuAjE6bqBlsknDFiLu5p4Xq3K8xytKHv5snne3p2YMW4UctukNCvPCwsPx/UDBuGhRx/Dli1bZPsKi4kFRVGwGAyywZLiBFgvBSVpkYrRaBWvr0ogOcwOu92t4Ukawzv35ovuBynPOyHwPIqikN2uLSLjE5GcnYOI2Hg3nnf65EkkZ+fgyPFjbvbWYbffgWdfXCjuX8rzWEkTe8GCBejevbu4Hjn306ZNE+857C48b/z48W6WXRnPc5mQ68rzpOhzU3+8+tZ/YbdZYTUacO8DYxGTkub22as8z3+0gktJYKND3/5Ize0Mu9WCX7/4xONyTitDjFsuCCCx61ZWikWv6GTvRT6NTocUIZDZ25Rdsj1vk3Xjw51KvvoGpuvWlpfi+9deButwoEOfmzBw3GQAzkwYVzjsNtECTLqpqUnxKAzilXscx4JmNKI11xWkMFjrYfiGQSDW3shf54G3AAAOb9kodlU4jnMq+SR2XcBp4wi04RuE/F0NHd4E1cYhgojfWtquazQasWTJEkyaNMmv9b799lvcd/sQJCanYuWadTh27BgeffRRvPjii7j//vvdOp2ffPIJioqKsH37dsTFxeH222/HmTNnxNeHDRuGoqIi2WP58uWybbzwwgsoKirC8ePH8cnHHyM8PAyjx43H2x9+BHBAbXm5R0UdISiUh1wQQlwcdruoiGvIxkFRlCSXz0senkRhd/z4cRQWFuKrr77C4cOHcd+9d8PhcEDLUABFYfasR3Fw1w7ZeZg5c6Z8ew47qkuKwLEcdCEhohqHdbCeJ78RgiZ8V0ktuynJyViz9gdYhOKmneVgNpuxbNkyZGRkOO26ku7xkiVLMHPmTPz6668ouHiRP18uSr66ujq8+uqrAJy5qG7HyHHI+9tonD97Rvae//3vf4uLTJgwAV9++SUqKxt/SrwKFQCQltsZN435OwDgl6Xv4/zB/QCAeqFB6mm6LiAvACpFlHhCaFQ0zwk5DgXHj8heI9wrsoHJuvFh8iKfkl3XG/+MFAZn1Pho19UytGgpLfFhgJY0m1oKk5DHRzJCG0JoVDTSO/PKx9P5uwA0pOQL0GbuVcHzBMdGvcrzWsvgjSvheXffxvO85d82L8/bt2sn3vrPvxEdHYXBgwdj4cKF4jJavV50kdVXVopNElJ49JTJB8gdB75M1hXXo2nRNmxziUYRnRLCfl153r13CzxP4PvPPvM0DuzYjqP7/3Djec4hae4FSJGLCe4Q+TF4t8Wmp6djxYoVsFn467bDhedJzw1RGEp5XlFxsew9Ekh5nhTk3JqFWK7x4x50++xVnuc/1CLfFYKiKNw84SFQFI3jO7bh4pE/FZerVwgllkK061ZViMq7GA+TdaUglt0Lh/Z7XEZUBiYrKPkk5C9MnPxW5fHmz2YxY81/FsJUW4P4zLYYOu1RRAsDM2pLSxVlwfWVleJ0sxDBeqthaBTHdhCXiUxI9BiyKSr5PBX5qrzbdQGgQ+8bodHrUVVUgMITxwDwBTwSpkoKiQTkJjPQinzlV1Emn9OuqwYyEyVfSw/eWLduHfR6PXr35u32LMsiLS0Nixcvli33xx9/gKZpnD9/HgaDAVOmTMGw4bdj/r/eQIfO1yAzMxOTJ0/Gp59+iq+//hqrVq2SrR8VFYWkpCR06dIFixcvhslkwoYNG8TX9Xo9kpKSZI9ol4mW4eHhSEpKQkZGBnpffz1eXfgi/vnoP/Dyf17F6bNnYTUZYTEasHXrVtxwww3Q6/VITk7G3LlzYRGIDaPRYODAgZg5cyZmzZqF6OhoJCYm4pPPPofRaMSMWY8hOaMN+tw8GL9s3drg+XPm8plw4MABDBo0COHh4YiIiEDPnj2xd+9eWX5KQkICkpOT0b9/f8yfPx/Hjh7FxXNnxAl2YaGhiI+NRUJCgngeQkNDZfusr6iAw2YDo9UiKiFJLEZy4BSHY0itJNKGFLHsdu3cCSkpyfj5R17B5GA5rF69GhkZGbj22mtBUcJ0PYFE1tfXY+XKlZg+fTpGjBiBz5ctA+BO/mbOnInXXnsNpaWl0IeECq878wk5jgPHcQgODkZqWrrss4+IcE7N7Ny5M1JSUvDtt982+HmoUHG5uP7Okeh00yBwLIv/vfEyqooKJNN1PXMRaQHQU1HOE5y5fHLLLlHyRXtQBroq+UK9FvkKhG25x6dECJl8hqpKtxxqJ8eVv3fSrPNFqUUKcfUusSrSybq+Kmk6CFN2IXx3hnvN5FNW8lmMBhhra3zanyvKL5zDn7/87DWa4XJxVfI8H4rATQGWdYjZ3P7CZjZj/08/uMUAXS5ay+CNK+F5t43geV5O567NyvOSEuLR54br8c7bb+PZZ5/F/Pnzcfz4cXG5PX/sx4hRf0Objp3Rpm1bzJ79BKwCz6MZZZ734YcfwmQ2Y9acucjudi169O2L9evX+3wedUHBOHz0KIYMu03G8/bs3g3AaUl15XlHjx7heZ4g6QyPiEBCfDziY2PdeJ6d2FsV4k/ItZLjOLc8P1KYU1oPAHr06IH09HT8vO57AO48T3r8DrtdxvOG33YbVn6zWmiSy8tMUp4nhdRiDQAhoaFun73K8/yHWuRrBCRktsU1g4cCADZ/8r5iOKZSl1MKUvyrr6xwkqwG7LqAs8h38fBBj6GcleL23ElbuXTiWpQzE8VTZ3Pr5x+j9NxpBIdH4O4n5kEbFITQ6BhodHpwHKv4ZUlstmGxcbKbRnNqJ7DgL0LebCvSCbtKIPJrbzk4uuAQdOh9IwDg8Bb+S4QUDUOjot1ycQK1yCfaOK6iDu9fwa7LcRxYq0PxYTfbwVkdgI0FZVde5koe/tyEbNu2DT179hR/pmkaY8aMwTKhcEPw5Zdfol+/fmjTpg1+/vlnVFRU4B+PPQZAHsh8xx13ICcnx607K0UwUb8pTFv1FaQbOePhh8FxHH75bTsA4MThQxg+fDiuv/56HDhwAIsXL8aSJUvw0ksv8+9PIECffvop4uLisHv3bsycORP/ePRRTJn5D1x3bXdsWv8DBtx4I6ZMmw5jA4N6SJHPZjEjLy8PaWlp2LNnD/Lz8zF37lxotVrYPWTlkfNgs1qhYfjrJiFx3ibs2ixmUDSN6KRkPjdQsAADzglvUjjEnBpaLNgBgC7EWTzMu/9+fLP8c355lsPHH3+MCRP46ApC6kiRb9WqVcjNzUWHDh0wduxYfLFsOTiOc+sgjxkzBtnZ2XjhhRd4m7VwA05s1WR7FBrOebnhhhuwbds2r8uoUHEloCgKt06dieT2HWAxGPDtv54XbZ/elHxSnuKpKOcJaR27AOD5nrGmGjarhR+UISr5lJWBrlm9IYLrQcmuS2JXXIe0ATwvInnFrlzP4GGwXEKE79NTpTxYtm2xyOd9sq4U7Xv1lalwwmIV7LqCks9utbiF8nMch+XPzsanT8yAxag89M0bfnr/Lfz8/lu45KHxfyUQHRuhVwHPE4azlNVbmqQg2hD2rPkGHz4yESd2bfd73T83/4xNHy/G76uWNbwwvPM81uoAa+F5Hm1jA5bnzXrscQDy6brNwfOIYEOr0+PRRx8Fx3FYs2YNAKCgoADDhw9Hr9698evGDXjlhQX45ONPsOjNt/j3J0SHuPK86dOnY9zESbju2mvx85pvMfjmW/Dggw82yPMIdMHBmPH4E0hKTMDOHTuwZ88ezJkzR+RfSio6Gc+jCc8Tsu8UMvkaGkZGKzgr+J+Jks8zl5o4cSK+Wv4Fvzwn53nS42ftdhnPu//+v2HF198ouhalPE8KRquVLU9TDZenVJ7XMNTxJY2EvqPH4tjvv6Lswjkc3PQTug8ZLnudBL17LPLFkKEXleKkmpgG7LoAEJ+ZhaCwcJjr61B8+oRbsDHHsuKktJgGlHwaLT/5zVxXC0NVpVjokoJYH4Y89A9ECNYNiqIQlZSM8gvnUF1c5GbzIPkqES5quZjYWBQGJSPNXIgoLx3tBpV8ZPCGF2INAJ0HDsbhrZtwfMc2DBo/VbTqhrtYdQFnkS9QbRxXx9Q1nsCW11vAslyLdzebEpyNReH83z2+TrQR7iapK0fKC31B6XwLEz5//jxSXJoFeXl5WLRoES5cuICMjAywLIsVK1Zg3jw+8+3EiRMAgI4dO6HS5h7gm5ubKy7jCqPRiHnz5oFhGAwYMEB8fu3atQgTbtAInn76aTz99NOK2yFFvsSkZCQkJKCwpBSMRoMlSz9FamoK3n77bVAUhdzcXBQWFmLOnCcxY+J4MXuvW7du4vt56qmn8MorryAmOhp5o0eDoig8PnMGPl22DAcPHhS730rQaLVgtFo4bDZcuHABs2fPRm4uP2m8ffv2AIDS82fc1isqKsKrr76KpOQUZLZrLyr5Xvz3f/DKa6/L1C3r16/HTTfdJP58x+j73ewoJpMJnTrm8tbgoCDZa84sFbk1haZpMaNrzKhRePGVf6Hw0gVYqvTYvn07VqxYwWfh0PLC45IlSzB27FgAvP2mtrYWO3btxvC775Ztn+TM3HHHHXjssceQkcZ/X9ltNn6KsUBSl365DMu++lq27vvvv4+8vDzx55SUFPzxxx9u51GFisaERqfDXU/MwxdPPybaXBmNRlS9KkHqOPBfyccX+UrOnMLiqfzfFEXT4g18tMLwMkBJyScM3vBm11VQ8lHCNODyC+dQW1qC2NR0ALz611DNb8uV4yYKSr4SH5R80gF0UjiHbvhe5AsOC0dmt2txZt8eAMpKPl1wCH/+WBZmQz3CdM7Ppq6iDBWXLgAAik6dQOY11/q8b45lUX7xPAA+Ezu98zU+r+sLpDzPbrX6PLylNYJwVZuDQ7XRhuhmzhk8uz8fAHAmfzdyevXza93yC+cAOHPPG0JDPI/8djeOLlCO5uJ5nTp1QqmleXmeNPdOo9cjJjhYNjTk3XffRXp6Ot555x1wLIt2WZkoKSnFi/95FY8/MkNsBijxvLi4OIy9/28AgGeefhofLlnSIM8j0OqDUFBYiIenTEJsMH/t7d/TeR1xVdERnpecIvA8oZn7zLx5eE7IJiZcj/A8wrMG3zbcTTVnMpmQm53NnyOXhq63wRsEY8eOxVNPPYXCSxdgDNbJeZ7k+B0Ou4zn3XrLLaitq8OO3XtwV5ss2TZdeV67du3E54NCQ2ES8vre//BDfPKpfLCVyvP8h6rkaySERESi32j+F3z7ys9hcikOebIyEIRGxQAUxf/hcRz0oaHiVFlvoGkGGQKBUMrlqy0vg91mBaPRICIhwe11V/JH8mLqFaauWYxG8X0QsklAinRKE3aJAs81EyUhIgi7oq8HEjLQZdCtHt+jqOTzOHjDtyJfWm5nRCYkwmoy4eTuHagtUx66AQRmJp/RaofRyl+4r4asFqI6sDk4VJvcFUcqmh8mkwlBLkWh7t27o2PHjmKXd+vWrSgtLcWoUaNkywl8RdbhJdC53KSMGTMGYWFhCA8PxzfffIMlS5bgmmucN0qDBg3C/v37ZQ8SyusKjmWdXd6gIF5FRtMIi4nDydOn0eOaa2Qd0n79+qG+3oDC4mKR/En3zTAMYmNj0VEoznEch/h4/trmakFQgl5Q882Y9hAmT56MwYMH45VXXsHp06fBOhxiGDQApKWlITQ0FCkpKTAYDFi89EtodTo+kw/AI9Mewsbv12Dn9t/E83DdddeJxwUA77/5Bvbu2S07V9d27wbAnfgB0gm27uSPDA9Jb9sOg4cMw/dfLcfyLz7DiBEjECdkqjrtujYcO3YMu3fvxpgxY/j1NRrcdfsILPvqK8XpukOHDsWNN96IZ599Flq9nt8WxwlT1/jjuu+eu90++zvvvFO2neDgYJ+77SpUXAlCo6Jx9+xnxfylkCjvllJSYAPgtbmphIj4BOT2GwCt3nkN5lhW5IxxbTIV1/M0eMNYUy2z7HMsK6oCozw0mSMT3CfsGmqqwHEsKJp2U9slCko+XzL5yLYvHflTFlZvFAqIIZHeOZ4rcvvxBQOaYUT1ohT8jaVyLl/5hfPi/0vOnPJrv/VVleJ3jtKQkitFhdCcrz+0E2+OG4nDWzc1+j6aC3oNg6gQvnnU3K4NjuNQfvEcAP8/Y8BZEK8tLW7Mw2pxNAbPc7CcmDFI0FQ8j6j9NTqdWOjiOE68Dh89ehR9+vQBRfGTaqMSk9Hr+utgMBhQVFIqrqPE87p27So+lyI0Hn3heQB/3Xlk+nT88+l5GD3u7/jve+/j3Hm+cUBRFBgd/3vvyvPeX7oMWp1OtOs+8cQT2Pj9Gmz8fg325efLeB6x6375+edu5+q6664T1XHS6ynLsmKRz5NdFwDi4+Nx69Db8P1Xy7HiSznPA5yTgY8ePiLjeTRF4a4Rw7Fs5UrF7Up5nhTSyfAPPPCAyvMaAaqSrxHR7dbhOLjxR5RfPI9NSxZjxMwnxD+whuy6JK+OdFZjktN8zh7J6NodJ3Ztx4U/D6DPyDGy10geX1RSimLmnVuHNzoG5RfPixNrpags5APTQyKjRJsDAbHbVpe4T9glSj5XxVxihB6FQSkov6E3EjLbenx/pAhnqKyEw26X3XxazSZRpeMtkw/gO96dBwzG7199icNbNiBe6DAoK/kCr8hHurt6DY1QHzt2rRk6DY3oEC2qjDaU1VkQcxVMkvMESksj5YW+iq+ZrHacLjNAy1DokOSurm2MffuKuLg4VClM387Ly8OyZcswd+5cLFu2DMOGDUOsYI8iCrWTx48hKqsLHCznRsCkk70A4PXXX8fgwYMRGRmJ+Hj3v8/Q0FBkCx3KhkAsbTTDoLqmBmVlZcjKykJQWJh4TawtK0VUUorbNZdca7QugcsURckIq1aYrMsqFDBdoQsOhrG2Bv+c+QgmTJ6CH374AevXr8dzzz2HLz77DDdd1wOUQO62bduGiIgIJCQkIDw8HKdK62G02kXyFxcXh6zMNgiPjXcbPETsGakpyeiQ21H23oKFQiNZJiIiAjVCuD0rKfJVV1cjUnLTTjMMdEHB0AUH44Fx4zH78UdBUxTeX/yucxmSA8NyWPLRR7Db7TJVAMdx0Ol0qK+vR4zLjQQAvPLKK+jTpw9mz54tfn+a6mrFm/HIyKgGP/vKykrF3xsVKpoCiVntcNuMx7H2jX8huV2O12WjkpIBikJEXAL0IQ0PkXDFiH8I06tZB2xmC2xmE6xmE0KjosXhOK5wL/Lxf9Mcy8JUXycq5OoqyuGw2UAzGkR4+PuJFAb3SIdvEH4bGhXtxjOJHdMXJV+763ohJDIKNaUlOLxlI64ZzE/SJLl4/th1ASD7+t5I73wNYtPSPWY+B4WFw1RX61bkKxNUWgBQcuakX/slxR8AqLmMvDebxYyy82eR3D7X7TvJZHXAYHWA5hw4tvYbgONwJn83Og+4xe/9tBbEh+lRLfC8DknhDa/QSKivrIBFCPqvuHQRNrMZWoXvJE+oEqzt9VWVsNtsDQ5mcOV5dosZtEYLmmFgs7M4XlIHChQ6pYT7fP/nK5qL5504fgwRbTqDA1/oo5mm53k2iVUXACoqKkSepwSNTocwQdmr1Ut5nDvP0+v1/HRXmhI/X194HsHL//kPJkyZgrVr12L9+vV49a3/4ssvvsC9994L5gJ/f+7K886VG1BrtomDN+Lj49G2bRY4lkVcehtRucs6HOCEYl2bzEy3cxUcHOyMT7HZRJ5Hmtr8+6LdeJ4UY//+dzw+y53nATyXZbRafLlypSLP0+v1qKmpUdy2lOc5txci5jFHRkaqPK8RoCr5GhE0w+CWSdNBMwyO//4rtn7pnLZb7yGvRArpa77k8RGQXL7CE8dgdZniU+llUhrLcqgw8IUhschHlHxKRb4C/oJELBpSEGtHTYl7R4tk8rkp+cTpqd47vCERkWA0GnAc61Z8JD9rg4KhE7JivKHzgFsAisKFQwdx6ehhAMpKPtGuWxc4dl1p7k5jE4SWghjafZUP36AoCrSOUXxwGhrQ0mB0Go/LXMnDn9+Va6+9FkeOHHF7/oEHHsChQ4eQn5+Pr7/+WiapHzp0KGJiYvDmG6+Lz5Fcvu+//x4nT57E+PHjZdtLSkpCdnZ2o3yBiwRQH4S33noLNE3j7rvvBkVR6HLNNcj/Yz/MBgNqy0rBcRy2b9+OsLAwpCQlebUySG8aGa3vBWitkLlit1rRrm1bPPbYY/j5559x7733YqlgTyC22KysLLRr1w7hQtPB7uDJpW9ZLQ1PXSOZfB06dEB+Pm9bkk5d27dvH3JylIsWQ4YOhc1qg91mw9ChQ6UbB80wsNvt+PyLL7Bo0SKxE7svPx+b1n6PpIQErHQJ4Sa44YYbcO+992Lu3Ll89h5FwW6xiDdjrpYUJRw6dEgMh1ahojmQ06sfpr67FMP/8YTX5SLi4nHfM/+He+c+d0X7o2kG+pAQhMXEIiYlzWOBD3CfrstotGLRXGrZJfnNUYlJHotiRG1XK1GoeYujSfBjgJYuKBg33MUrg3asXiHm5DkHb0Q1uA0ptPogjJ7/Em6ZON3jMqKSzyDP3au4KFXynfZrvyRXG7g8ldf2lV9g+bOzsXvN126vEZ7XyXRKzEGsKLjo9z5aE/zJbWxMlEsKuRzHovT8WZ/XtZqMsvsRX4Z3SHmeg7OhsrQQ1RXFoLQ0OK3A8/Q0GH3jc73m4nmvvfYaGJpGkMOM6oKLsFstTc7z7ILQg6ip33zzTZHnAUDHjh2xY8cOWS7hnn37EB4ejs7X9nTbnhQUTSM6ORXRyamXfV+Vk5ODxx9/HBs2bMC9996Lzz7/XJYr7MbzBH5MmrmAM4dYmr0vzdnzlFPsVPLZRJ5H3CK0RgOKorzyvGFDh8FmtcHmyvPA88+g8Ah89e13eP6Zp0SV4W+bN/E8LynJYw6jlOc5t0chOjkFGp3Op3Ot8ryGoRb5GhlpHbtgyEP/AADkr/0We/63GhzHiRkjXot8EiWaUlHOEyITkxARnwjWYUeBULgiqCoSJusqFA2rjFY4WA4UBVElRdRwZJiFFJUCkYhRKPIRJZ+SXdebkg9ouMNL0bQ4/Zbk6BE48/iivG6DICI+QbQ3E3k+yRaUIigAB29UXEUT1wgI+Sv7Cwzf8ASHwEtaQybh0KFDcfjwYbcub2ZmJvr27YtJkybB4XDIZPWhoaF4//33sWbNGvzf3Fk4cfQQzpw5iyVLlmD8+PGYMmUKhg8f7rorr7BYLCguLpY9ysvlSTZ1dXUoLi7G2dOnsWP3Hjw+9ym8+OKLWLhwodghnPmPf6CwuBjPPP8CDu7/Ayu/+ALPPfccpk2aCJqmFS2lBJTk82iogy8Fw2hgZzk8veB5bPz5J5w/fx7bt2/Hnj17kCMcl1IYMsdxIvkjdl2DyYjSsjIUFRWK56G2lr9mEQKo0Xqeukbsuo899hh++OEHLFy4EEeOHsGxEyfwwksvYceOHXj00UcV34dOq8F3m3di3a+73TL/GI0WGzZvRlVVFSZNmoQuXbqgS5cu6NgxF7k5Obj9tmH4+JNPFLcLAAsXLsQvv/yC48ePi+eWKLZNZrPbZy/9fTQajcjPz8eQIUM8bl+FiqZAWHSMWKD3hjZduyM2LaMZjohX01S6NHMBuWWXgOQ3e2syRyTwwz2UlHxkcIYUiX4o+QCg2623ISw2DvUV5Ti4cb3sGP0t8vkC4kpxt+ueE/9fW1biFxeUFvkuR8l3URjWsWv1SpHjElQYrADHoWf1fsn+Cj0O3muNuHjkT5w/uF/82dnwb16eVy4p5AL+KTalak2A/x3xB1YTL8iwWyww1dW2msm6wJXzvBeenIlLh/bg3NkzeH/x4ibneZcuXkJBYRF27tmDqVOnuvG8hx9+GBcvXsTMmTNx7NgxrFmzBs899xwef/xxjwMrpNAFB8siEnyFyWTCI488gi1btsh4XseOHb2u59rMraurQ1lFBUrLylBYWCDyPKXBaa6Q2nUJz3vplZdx4tQpnDh1Cs8884xPPO9/W3a58TwA2LhlK2pqa3H/ffehbXoaunTpgtycHOTm5ODuO+/AkiVLPB6blOe5wmg0qjyvEaAW+ZoAnQfcgv5jJwIAfv3iY+z/aa2Yz+Epkw+QFwBj/FDyURSFNl35jCXXXL7KQp5sKA3xIN3dmBAdtELHgGTyGRSk2hWCks9bka+mpBgsKycbYpEv1rXIR8hfw927cA/DN5xFPu9WXSk6Dxws+znCy+AN12xFgn3rv8eBDb6PUpdi89IP8MVTs8Sb1saCc+La1VPkI8qDlpiwW3TyOH755H3YzP5/TucO/oGP/jEZ5w5eeSgsIX9MKyB/Xbt2RY8ePbBKQYWVl5eHAwcO4J577hEnhBHcd9992Lx5M4oLLmHCyOHIzcnG5MmTMXfuXHzwwQd+H8ePP/6I5ORk2ePGG2+ULTN//nwkJyejZ5++mPnEbNQbDNi0aRPmzJkjLpOamop169bh4JGjGHz7nXj0n//EuLw8PPown/vCeJk8Jp0ExigEn2dmZmKBEJbsiuCwMFRVV2Py1IeQk5OD0aNH47bbbsOcfz4m7Ne9UMByzowbcfDGSy+jW59+6NC1m3gennzySQAQVTBK2yLHzjocYB0O9O3bF+vXr8f69esx/K57cG/eWOzevQebNm1Cly5d3NYHAA1FISw8AsGh7vYqRqPB8lVfY9DAATKrBukg3zFiOPbu3YuDBw8qbjsnJwcTJ06E2WwWu/MEn3z6qdtnT7JgAGDNmjXIyMiQDR9RoeKvCqVmLuCcsCst8hH7YZTC0A0CpUw+ZxyNOw9LlExPdQ3jV4JGp0Ofe+8HAOz67ivYzGaJXTeqwfX9BcmBkhb5HHa7yHd1wneZP5lt0iKfqbbGzWHjDQ67XVQR2ixmbF/5uez1inoLsoznEGGphC44BBq9HqzDLmYptnY47HasfmUBVr/ynPi7R4rPzc3zSCH3Sj9jwP/sRZIjB/B/Pw6SkdYKXDhXwvN+2bQJJRfP4e77H8ANA2/GI7Mea3Ke1/WGXuh7y2BMnDwFNTU1Hnne7t270a1bN0ybNg2TJk0Sh2xcCbzxPIZhUFFRgXHjxsl43vPPP+9xe0rN3Pnz56Nzj+vQrU8/ZGW3F3mew9bwJGJaouTr06cP1q9fj59/+hl3/W0M7hw1Gr///rtXnsfQnnkeAHz88ce4eeBARISHw1BTzQ9JE36X7777bp95nis+/PBDlec1AtRMvibC9XfcC0N1FfLXfotfPnkfAKAPDfXaDZDbdd0n4XpDRtfu+POXn3H0ty0wVFdBGxQErT4IpWdPe9we6ZrFSYY0+KLkU7LrhsfEiVMj68rLRSJos5hhFjqg7oM3nNNTHSzntYhBCnG1Hot8vgcyt7+hDzYFh8BqMgrbVrLrCsSvrlaWH8YfQyk2L+W/sNr36uvXxDeWdeDAxvVw2GwoPnWiUaeulYsT1wJ/6AZBPLFx+KgCaExs/eJjFBw7jKjEJPQYfpdf6x77bQtqSopx/Pdtfk3lUwIp7LSCGh8AnnDMnj0bU6ZMkVknp0+fjunTPduibrrpJixd+R0MVjsSQ2iMGzMKS5cuxYQJE2R2DY7zfiO4dOlSLF261OsyZKqaw25HmWDBSchsq2hpGDBgAPbm56O+qlK8WSWgGY04Scx1+8aaavF6pNFqZcdtNBpRUlKCgQMHKh5fWGQUFr/xOmiGhi44FBRNgaJoWAz1cIAPnHY9DzZB0slQFGiawrlz52AxGlFVVACNToe49Day5VOTk1B06gSiEpPc9r9lyxaUnj8D1u6Aw24DzTAYMmQIbr31VpSePQ2O4xCX0QYaFxuy9LyT67X0xv27774DwDdjPvvwfbfrMrEVX9ezp+z9KX3m77//Pt5//31wHIeyC+fA2u1YvewLxeOS4s0338T8+fM9vq5CxV8JhOdJm7mAc4iFrMgnFC6UJusSRArOB3N9HSxGI/QhIaJtUUnJFxemA0Xx14kKg0VUbXlD54GDsef7b1BdUoR96793Kvn84Fq+Qi8O3qgXn6sqKgDrsEMbFIzM7tfhxI5tKDlzCpndevi0TXeVV6nb9dkTKgsvwWG3g2Y0YB12HNq8EdfedifiMzIBAOV1FlxXsw8A0H3oCJw/+AdKzpxCxaULiPHzvqElYKypFkUPl44eQk7vGyWW7ubleWVCMbVDn5vw5y8/+1nkuzIln83C83VKGLhorasBoGsVSj7g8nnetV06Y/nHH4EDBYvFjAnTpjcpz7MYDagqKoRGq0Nchue/sQEDBmD37t0eX/fE81zhD8/T6XQe7aoAMHDgQLfz4HBp5pJjqC0rhbG2BmHRMWKtoKa0GOlpaairrFAUEG3ZsgUcx4mczmG3Y8iQIejT41oYaqoRGhXtdl8OuPI8oSHMcWBZDjRNiTwPAP73v/+B4zhUFlyEzWKBsbpaLPL16tXLZ57netwNQeV5vkFV8jUhBuRNQMebBok/KxEgKcTXKUpUxvmKjC7dwGi1MNZU49j2rfhz00/Yt24NzPV1oCgaMamei3xSC0eoByWfw24TO4Uxae7bomgakYKNo1pi2SUqPm1QsFtmTGyoHjQFsJxzWpgnECWfq7yekMvQaN+LfFp9EDr05av/uuBg6EPds2yCw3gln8Nuh82lC1ty1pnPUnTSXWbsDTWlJaJFTsnafCVw2nX1KDxxDN8vesnN3hxoIEq+sgZ+PxobHMui9NwZAHzWpb8gGTlKg2j8RWtS8gHAiBEjMHXqVBQUFDS8sAvIe9Do9FizZg3GjRuHX3/9tbEPUQRRy5KpsN4QGhUtU4qQvBJPkOb1uWbybd68GTfffLNH8qcNCgJF02AdLMz1dTDV1sJYUy3m4Wl07oV6xZwWDclpkWfycRwndnk95QVqNPzzUssHyzpEIuZt6hogKfJx7lP0aEE9KFUr8MfZ8EQ3V1AUhWDJ1DVv65aXl+Pee++VdXxVqPgrQ4nnAUCocK0zSO26xZ4znAl0wSFinEmNkDfnLY5Gw9CIDfWvWcdoNOgz6gEAwJ7/ffP/7J15nBOF+ca/M7n3yt73LruwXHKLgoAHKiqi4H1BVSxCtdVWbcWzaD1aq7VWW7XaetGKrdUq/rxRUSl4gXJfcu1y7H3v5s7M74/JTJLdJJusLGQhz+eTD2wymUxmkswz7/s+z4PdZ0EQSzM3WmiTfJ3+Ip864ZVdUkr+ICVQINoCkOT1avvF4itKRuPXpqLexzsKBg9lyMQpyLLEZ/94TvtdrtuxmXxnHbKo59izZ2lNd9UzO94RKD/eu3kjEDjJd+g8+SSvVxtcGHGKou5p2r8vauWGOvWqHuNYZNmyJGnnZ7XI4ulsQydLcTHJB73jeS67TTu+bYY0zBYLL/z1aeZccUWf8TzVc7nrxP+hQE88rzfweP18P7DgG8qTT+VukexiBEHQ1ByqhYvXxxcj2dForyuAQPeGbtfXUH/7FR6rvE4oee/BQILnRY9Eka8PIYgiZ133C63711PhTv2xT8vO1VKCokVSmpUr7nuEM+bfwNSrrmXKpT/i+PMuZuxZ5zD9ZzcHXSSpCFnk83UDOlqagqruzdUHkCUJo8UStlgZKmG3vUGV6mZ3T64UBe21e/JrKRujmKNuW7UiyCtFm+Szxkb+xkw7G1GnI3/QkJAX8nqTSZsWsXcJ36jbvUv7f6xFvqYAg+TWXsgrZFkOS0I0uW6Sjvef+iPff72KDZ98GPNrxBPUZL66KCTdBxPNNdVacbd6R2zHWO1qAbSECKKJBpIkad8/tYASL+QP4KabbqKkpPtEb0/QB0x/mc1mbr/9di666KKDvXkaAkM3eoIgCKRmZWseTfoevLXUYpMgit0KiOeccw7vvPNO2OeKokhmYTFpObmkZuWQkpnlKzJaScvJDUnaNJ8Wnf9zoG6D5JWQAxLfFBmub/kwBFDnu98bWORTQzd0uiA5csjnBxDQruTPlKTIeJw2m+Y9FLT+KHxwAmFJTUMQBPQmU8Ttys7OZuHChUdM8FACCfxQhFJsQHdPPq/Ho52vMgrCT/JB94Tdjh48p/N6EawwbMrJZBWX4uzsRJaV3zLVRuVgwhLCk69hbxUA2aVl5JUrvl61u6Mr8rXW1yJ5vehNJgqHKN5brTGEb9QFTJ6fNHsuOr2eyvXfsWetEoxk/2YZAFLFcSSnZ2j2OY37qqJ+jcOJwCLfvi1di3yHrpnbXH0Ar9uNwWSmcMgwUjIylfCNPbt6fjL+qVc1+LAtBrmux+1ClmVEnYglzarIhWWZZG9n3DRzITaepxS3ffvAnIxTNCLrTZhNJm668Wd9xvM8Gsc79EW+nnheb6AW+fRdeI6ocT1/Q7enRq4Knc+XWeV6qm1KJDsaFYIgaJ9JT4TpS6MlCYPZjCzLyD4+KPRRkS/B86JHosjXx9Dp9cy65U5OnbuAk+f8OOKyJSNGMeq0Mzl5zjW9eq28gRWMnjad8eeczwkXXc7Js+dy+o+v55iAacJAhCrypfi87TxOZ9DFmRa6UVgc9ouVESJ8Q03WDeV7B9H78hUNHc7giZORZYlPA7qaWpEvgtdhyNcdWMFVj/yFc2++PeTjgiBg9kl2uxou1+0JnOSLbcqrcZ+/yNfSi0m+z/7xHE9eewV71n3bfd2+ST7Tnu80KUGotOP+BE3GcYgn+eor/USvrb4uZNp0OHQ0NWrfnY7GBtyu2Lbd7XBQt3un5j8ZT4bMPxQ6nYBRcuFta+zm3dkXUAviBnN0psmCIGDNySMtO6dbUFBX6E0mpSiXldMrsmEwmUhKs5Kcnk5KRiapWdmkZeeGlaT5yZ//tQRR9IdoBHV4VfJnCFsUC1XkUycJowkPCCR/XYt8eqMJS5pyQd7e2KD9Xqvb2NNUZVfojUayiksjyggTSCCB7tCSdVMjF/na6muRJQm9yRTROxq6J+xGCt6A2MM3QEkPnnLpj7S/zalpMf9uRINQnnwNe/cAkF1SRt7AQYBfLtcTNMlzXgHpeWoxNPZJvpyyctLzCxg7fSag2IfU7tqB7sA2JATSJpwBoAW49JeE3UAroIaqPdjb2w5L8IZ6jLNKShFEkTxtYrPn8A1ZlrXjrA5xtMYg1/X4pLp6o0lrLgKYvQ503p7DFOIR7Y0NeD0edAYDulRl6ELSKcUnVy98raOFyq8PxyRfX8AjdW/mgp8zqRwqsJGr6yH4zT/J5/GtI/pJPghQbXjDF/kEQSA1sMkjEDahPYFDh0SR7xDAYDZz7NmzegzT0OkNnPmTnzN00okRlztYaFDJX0CH12A2Y7QkAcEn48YIyboq0vOUC7DA4pXqWRVK9w/+VK3aKDq8J8/5sdbV3P3damUbVS+YXsg4sopKQk44qlC7xo5uRT5/Aahm5/aYihWBk3y9mfL6/utVeN1uPvr7k92COxo6nIiyl7Yv/IEgLTF0kOMR6oVJ/SH25KsLkGRDbNN8Xcl2LB1eAIetEwBbWytOmw1Jir9Jvt5CL4qkejoQnLZuE7IHG7Isa9+RWJLRBFEkyZreY2dYEATSsnO1YlZfw+0jf4G+WoIgaFNxQR1eX+hGJO+6yEW+GMlfCBlHSkYWgigqvqy+C2gpRnIZCL3RGPV2JZBAAgoawsl1fcEbnS0tgF9+mJFX0OMUb2D4hsth1/yNe5rkiyZkLRAVEyaRN1CZpEvug9ANCO3Jp6pFckoHYEpK1iYb66KQ7DYf8Eue03KCi6E9QZZl/yTfgIEAnHDhZZhT02jcV8UbD98HwI7kQeT4ricyA+S6gdPc8YquacH7tm7SPpvtDg8O96FJCVatf7JLygD8E5tRHGN7exvOToWnlfpCD22tLVGH6WmFKZ9iy2AyI5uU6y7R3upvirnd2NpaaamtjqrAfLjg6OzQhiGsOXnofRNiblHhGG6Ho0cPvt5A8no1/hKr+i1eoXovG8TQRT5Vrqs1cvX6IM/EUFAn+SS3G1mWY1ZU+K1ZIv++GC1JWv1A1OkSk3ZxgESR7yiG2uHNTg2+ENTCNwKml5oiJOuq0OS6NQFy3TDJuipyYwhWCAxA+PQfz+H1eDQ/maQ+8GpRwzcCE3Ztba10+N6T3mjCZbcHTef1hEBJRUvtgZhOfLa2Vs3bpbWulq/e+E/wujtdDG/fhrO5XruIjrXAFG9QJwDanR46nZ4elj54UAu5anEoFll2U5ciX6zei54AotjeUH9ETfKJsgedrJAUd8CkcF/A43YhSxKCKKAPkX7b3xBqkg8CyJ+n+yRfpPetyng9Hn9CW6zkTx+hyKfT60nxeaV2NDUiSZJGUMUoZCIJJJDAD0d9iGYudJ/kU4tT6T1IdSGwyFdDR5PCExXf5aSQy+f4mrmxyjEFQeDkOdco1ioVQ2J6brRQJ/mcPk8+l92myQ6zfGEZeQOVKa+aaIp86iRfYZF/P0U55dXR3IijvQ1BFLUJPXNyCpMuUrynVE6+xjqWbF9hLD0vH51ej8fl7BZMF49Qi8r4CgD7t2wkzazHbFAuR2taD87U16bPPuZf9yykvakh5ON+30XfMR6kFPmiOsYHlGOcmp1DSkaWVthoq49u/6tetYGNRK85DRkB3E5a62po2FtJfdUe2urrcHR0BE3ExxvsvgJkcnoGRotF4wVuQacFiwQ2Ew8WVDsWncHQJ1O+hwP+Sb4ucl19cJFP3Z89TfGBf5LP43EjB1gBReuZF4nndUVqZhaCIMTUWE+g75Ao8h3F0OS6KcFfRnUqriNEkS9Usq6KdJ+UqrW2RusoqnLdcJN82cnKRWhTZ89R4AATL7gMS5qV5gP7+O79/9O6Wz3JS3oDc6oimwuU66rFn/S8AgqHDAWil+zKskzTAb85sstu7yYFjgS1w6hO53zz1uva1JgkybR02Dm+RfFtmXjBJYDSNY22uxiPSDHpyfR9RvY0dh6S15RlWTvOw0+cCkB1DOEbXb1xYvFeVKbPlO+lIAh43C50TuXiQ3cE/FoLLv9n0eWw9ylp1aS6JvMR0VEMFbwBgb58/iK4x6UaMkeY5PMRP8njRfL9Xsc+yadsSzjyl5SWrqSuezzYWpq1ImIswRsJJJBA7xE+eENN121W5IdRhG6oUD352urrAqS64TlYdoqP53VEx/MCUTpyDPP/8jxnzP9ZzM+NBuYunnyqH19yeoZmnZBXrkh2o5nyCtyPsU7y1e9RpviyikqCGjRjzjhbOy7VKQNoMOWQ5eNFok6nPda4P/59+dRCZdHQYwAlfEMQBEozlULZweB5Hrebz/7xHPu3bmb9Rx+EXKahyjfJ50tkVSf5mg7sw+WI3IAMPMaKxYeSON1a37NyRpZlzUcuMGDLK4jY9IqXraOjA4/LBYJSPAclrCNeJzVV3qAWOzUPN8nfKO+L6xC1MG+M0o6lP0Br5oaR68qShCRJWpEvEsdTESjX9cbgu6w9XzuePfN1g9lMdmkZ6b4gzgQOL46Ay8YEeouw5K/LJJ8sSVpxKtIkX1p2DqJOh8ft0gqEPU3yZahFPlt05M+UlKT5tKz89z9BlhFEsY8MmVVPPv8knyrjzC0fRMHgYUD0U16qV5sgilpKXODUY0+o3al4hVRMmET5uOOQvB4+ef5pZFmmxe5meOsmUr0dJGdmMeG8S7Q049Z+Ps1XluUjfw22Q/J6nc1N2FpbEASRUaefBUDNzu+DUq0iQS2Iq5/5WCb5vB4PkterSEF9xNHo7EAne48Iua7kDAhh8HoVIttH8MQQutEf4Paqct0u5E+verWEMGQ2hu/yijqd3+fFRxhjLvIJkcmfIIqaT0tnS7NWTDxSuu4JJBDvCBe8YbEqBSyvx4PT1umfQIvC9zLNdwHXWldLR3Pk0A2AjKTYeF5XpGRmReUT2huoPM9h60SWJL+Ms7RMW0aVDEdV5PPtx/T8Qq344+jswGnruXilNhdzBpQH3a/T65lxwy8ZOH4iyzMmK9sXcDw1yW4MqpLDhc5WRa6r2hLV79mN09ZJWZbCVysbI/O8LSs/46O/PxXR63jn6q+0BvrONV91e9ztcGhWNjm+45ycnqF8hmW5m11LV2jfFV9xVf0+tNX17L3o9XiQJEkJkgo4P3slGZsuCZ0lGUtqGul5+eQOGEhWUbH/PO05dGqWWCB18doNnPxS/ZB7KpwGwut201JbHbEwKEmSVpg3pxway5RDAa2Z26UAJwh+/2XJ6w3yXe4JoirX9Xi05NtYws8i2bKEXF6vj7qAmEDfInEUjlK4vRLNNuXL3t2rxTfJp0ahN9TjcTnR6fWk54Wvzos6nSZPaKlRpKhakS+Mib06pdUc5SQfwKjTziS7tEwbeU+2pvfJD4olRPCGSsJyywZSMFiZ5DsQ5ZSXOuGVkV+okbJYfPlUGUH+oMGcds116A1GqjauZ+vKz6hramd8ixLGccIFl6E3GrEGEPH+DJX8HapJPvUYZxYVk1c+CFNSMh6Xk/qAVOdIUKcrB46fAMQ2yadKdfVGI+aUVF9nVCbV04HYz4t8kiTh9b0/r6CQwViIX6xwBUzyHQkIL9dVCZzfkFm9GOipy9vVl0+KkQDqdD2TP1NyCkazRZvaFAQhQQATSOAQIVzwhsFoUlI9USS7LTFM8qXl5IIg4HY6qPd5yEUq8vWG5x0qqJ58yDJOmy0gdGOAtkyub8qrvbE+ojea2+XUArMyCgoxWpIw+xrQ0fAwf+jGwG6P5VcMYerPbqNRnw749ylAVrEvYbcfhG/YfNcVueUVpOcXIMsS+7dupixb4Xm7G8LzPK/Hzcd/f4p1y95l/bL3wi63cfmH2v/r9+yirSG4+NawrxJkmSRruiZbB78su3ZXlEU+X0HcP8nX8zFWr1t0RiOC4D8PemUZGQFTRg7W3DzMKala0SyU7268QA6w4VCbg+qEvyTL6NVJvhjCNzpbmnF0dNBWXxdW7eHs7ECSJHQGg/Y7diQgXDO3q/9yLHJdUfRP7anHIRY1RaxFvgTiBwmmfZRCTWLViwLpluAfia6TfKrHWHp+YY8TGOl5/oRdZ2cnbt9FfGpWaAKodXhjIH+iTsfUK6/V/u4LPz4IHbyhFfkCJvma9u/F0dnRfQVd0BQQXqIWS2Oa5POlfuUNrCA9L5+JF14GwKeL/866d/9LiteGzZjGqNOU1DVrnt83pz9DJX97IpC/gwltWrNsIIIoal5A0Uxs2tpaNX+SgcceB8SWouwOmD5Tgh2U4rhRcuF1HJpJxr6C267Ic72CDrvOrN3XF5Akye97cwRIOWRZxhvOq0UzZFYuADxuf6Gup99r1ZfP63Epr+Ht3SRfJPIXmB6obteRIJ9OIIF4h8sj0RKmmQt+X762+jrNzy0jCk8+vcGgyXP3b9sMRDfJ19zLSb6+hE6v1ySRjo72ABlnmbaMKSlJK35GmuZTz/Xm5BSNPwZKm3tCfVVw6EZXNHYq57Q0sx6j3n8eUJvG8V7kk2VZ8+RLTs+gePgoAPZu3hBVM3fflk3aROTqd97UppIC0VZfx5713wF+n/Cdq4On+bRjHFDIBbQk5drdkSc2m6t9BfFCX5EvN3pZtqYw6BIUoSpxdSG8l9WCTDxO8qkFvsDmnSigNaUFg/I+PS5XVGoYWZa18Dm304krDEdUhy8sqalHFJ/wN3O7l2cCwzc8Mch1BUHQJqHVxnosvsiJIl//RaLId5RClXBkpRi7GfqrnnxqCpZKHCL58alQfflaaqs1Pz5zalrYaRqtwxsj+RsweiwDjz1e2d4+8OMDtA6sGrzhcti1Dl5u2UCS0qxaUbNmx/Ye16ftx+KSgP0UXQGuo7mJjqZGBEEk1+cPc9zMC8koLMbW2sK+T5Yq2zHwJO3HXJvk60WK7+GALMt8uvhvfPn6v4Lu14p8B2mSr62hnsoNa8M+HjitCfhl2du39LhutZCbmp2jSW7aGuqiJmeqPEHvM2TWGQx06hW5sr2lMaYk575CY2Mjubm57NmzJ6bnqeTcLRpxC37C0Re+fOpEpE6vPyISWT2SjAwIdJ/kU9+fVzNkVpN1YzBkdruVIqHvRaJNv42W/BnMZm0yOlqpbkNDA7m5uezbt6/nhRNIIIFuUItCoZq5AEk+X74D27eCLGNKSsbi86HrCarfXO1OpSASiYf5eZ5bS4uPJ6i+fPaOtoBk3bKgZTTJrs82JRRaqoO92sA/5dXWw5SXy27TrD1yyspDLtPga853lV6rIR1N+/bGbTgDKO9RU+Ckp1NyzEgA9m/ZRFm2assSnuftWvO19v+Oxga2rvy82zIbP/0IZJmSEaMZPe1sAHYGPA8IKckGyFcn+SIcY1mStGKuJtfNUQNWei7kerok66rQAtZCFKzUc7x0CIt80fI8tTEYmKYqCILGDSRB0ApR0UzzeZzOoPfZNY0ZlIKhWvyzHEFS3eBmbvfPgcqdPE6n5s8YdUPWJ9lVi8yxTPLFErwRKxI8r2+RKPIdpajvUH5sQ3V3w03yZRZHU+TzJ+z6/fhCh26A35OvudMdMzk5fd5PGTrpJI4794KYnhct1E6s2jGqr9wDskxyRqYmaVYlu9FMeakpvFm9mORTp/gyi4ox+rrOeoOBafOu15Zp1achV4zX/taKfFEmux1utNbVsuadpax89Z9BHenyLFXG8cMn2WRJ4vUHf81rD9zN3k3rQy5Tt8fvuwhQqB7jHT0fYy2gpriUlPRM9AYjkterSXgibluAIbNaFJdkGZsuGa+gQ/J4tCTDw4kHH3yQ8847j7KysqifI8syK1asYM68axkzdiRjh5Rw6oxzeerZv+Hs0qkVBEG7Wa1WpkyZwieffKI9Pnfu3KBl1Nv06dO1ZQYPHUZBxRByywZisVgoKyvj0ksvDVpPPOPTTz8Nem/FhQXcsuAqDuyt1Ih0WVkZgiBgTk6hoGIIOSUDEASBhx95BID9NTUIgsDatWu7rX/q1KncdNNNeCSJU6bP4Oc33+L349Mpk3YLFy6kvLyc9vZ2XnzxRW1bdDodGRkZTJw4kT/+/re0t7VqiXAQfHwMBgPl5eUsXLgQfVIKlpRUktOV88uOHTu45pprKC4uxmQyUV5ezhVXXMHq1asByM7O5qqrruKee+7py12dQAJHLAL9+EKlsyf7Jvn2b90EKE3aaKdi1OkldYI44iRfsm9iWJJpd8TfNJKasNu0f5/C9wSBzKLioGW0Il+EKa8m1Y8vYBoyTUsijszD6qsUCWlKRqYW+NEVqgInKyV4ekcpKoo4bZ0hiyLxAnXbjJYkDCYzxb4iX82u7ylOUS5H9zbbNcliIGRZ1vz1ioYpoR3fvPV6UBiFJHnZ+OkyQLH1qThuorLOTRuCPBG7JuuqUI9xU/V+XPbQfLO9qRGPy6nYE/mKe7GkKLt9PsQGU/AxlNTE0xBX5apM81BO8kXL8zQ/Pt82rlq1ihkzZnDC8AEcX5HP8ceO5ZkXX8Tr9QbZs4TjeepxuvmOOymoGEJWUXE3nqdek02Yehp6oxFBEI4Inpefn8/NC65if+UerbCm8jxBEMgsKKKgYgipWdn8+a/PoDMYqKyq6pHnOZ1OJk89jV/ddbd2na0er2h43iMPPejjef5r9HA8z9GlkJvgeYcXiSLfUQp/sm6IIp/vIsw/yddz6IYKf5GvusdkXYBMn4zD5ZXodMU2pZSWncO5N91GyYjRMT0vWmiGzL7gDa34E+CXUjBEmfI6EEXCbpBcN8ZJvpqdfj++QJSOHMPIU88EYFXmCWSlJmmPpavEo59M8nUGpDlv+vQj7f9qh7ehw0m7o7s8Q0Xdnl1Url8b8TX2rPtWC5HZ8r9Puz3u6OzQyLjqi5PvK/I1Vx/oMQ1Z9V3MKipGEEWsajE3Cl8+r9sdYMisfC+8kjJc1aFXJg1srS1RScP7Cjabjeeee4558+bF9LzXX3uN8y+7nML8Aha/9jZvLv+aBddey+NPPc0Vs2d3K/C/8MILVFdXs3LlSrKzszn33HPZtWuX4jfndjP9rLOorq4Our3yyisAyLKSQnfrTb9g147v2bZtG4sXLyY9PZ1p06bx4IMPHrT90dfYtm0bBw4c4KWXX2Hn9q3cMPdybWIP4L777mPf3r2s+2Il675YyYEDB5g392oA9PqeZRxJKak88YeHeeXV//DB++8DIOoNfPnllzz22GO8+OKLpPom8NLS0qiurmbfvn2sWrWKBQsW8O9XXubS6SdzoDq4WTF9+nSqq6vZtWsXjz32GM888wz33X8/1rx8zMnJrF69mvHjx7N9+3aeeeYZNm/ezBtvvMGwYcP45S9/qa3nmmuu4eWXX6YpDorbCSTQ36AV+VJD/xaocl21SRmNVFeFWthQkZIRvshn0utIMSkXlb0N3+hLmH2+fPu2KMXOjPyCbuoTdcqrJoJc1x/I4N+P1iinvFRvw1B+fCrUycys5GDerjcYSM9XuIbKQeIR6jWF2iRPy84lLScXWZLwVu/GbBDxSjL7mrtLNBv3VdFaV4vOYODcX9yG0ZJE474qdn33jbZM1YZ1tDfUY0pOpmLCJDIKisgsLEbyetiz7lttOf8kX3CRL8margSmyTJ1u3eFfA/qMbbmFWiTVWpImqO9LWxxEND4CwRP8kmyrBX5Ik3yhZIn9wVi4XlSQHPwjTfe4JRTTqG4uJiX//uOwvOuv4FHH/sT1/3i5m4ezKF43tYtimJGbzAy7dRTWffFSrauX6vxvCVLlmDvUHi4IIrcd999VFdXHxE8759L/sXO7Vu58cdXaCFlgPYed2zexLovVrL+qy+Yd9WVUak1AEwmE3975q+8+t83WP75CkD5TEXL8/71ssLzqg/0zPMCi3UJnnf4kSjyHaUIl6wLkJyhnICdtk7cTodWnIpKrpvnK17VVGseJGlhQjcALEYdFoNyomzqiC/yZ+4yyaee9HPLBmnLFPqknDXfb4sYb29ra9XWk1lYrE3y2dtacdp6nlAL9OPrijMX3EDzrNvZkTwoqMOrFZjqauJawqFCTV0D2PTZx1rXMtVsINv3vsIlr3ncbv5z/1289uDd7PNNJYTCd+//n/b/77/+oltnVDW+TsvJ1Yq8lpRUMgqVrn5P03yNAYVcCC569wTVj09vMvlTtHzHzas3Bfgn1Wp+HIca7777LiaTiRNOOEHZPkmiuLiYp59+Omi57777DlEUqayspLOzk59cdx1nnn4ajz/2KKPGjKWopJQrr57L4w//njeXLuXVV18Nen56ejr5+fmMHDmSp59+GrvdzrJly5SEaocdna/rGXjL8P1uOTo6kIG01FTKBg6itLSUk08+mWeffZZf//rXLFq0iG3b/Mfxs88+Y8KECZhMJgoKCrj99tvxBHwupk6dyo033shNN91ERkYGeXl5/O1vf6Ozs5NrrrmG1NRUKioqeO+98EbgobBu3TpOPfVUUlNTSUtLY/z48Vp3U0Vubi4FBQVMmHQiP/nFrezYvpUdO/wXmampqRQWFZGbm0NuTg65OdmYfRcEYoRkXRV6g4ExI0fyi+uv47qf/ozWtjbcHg/XXHMNN954I6eccoq2rNppLigoYPjw4cybN4+PP/0ce2cnD//m10HrNZlM5OfnU1JSwvnnn8+0adNYtkyZsJBlmblz5zJ48GBWrFjBOeecw6BBgxg7diz33HMPS5cu1dYzYsQICgsLeeONN2LatwkkkEDkZi74i3yqTURMRb6cLkW+zMi2Keo0Xyz+y4cKqlx335YNAGSXlHVbJrd8IAgCHY0NYaflmgPkuir8fm2Rm631XWxCQqEhzCQfBCTsxrEvn1bky/D7aBcP90l2t27y+/KFkOyqktvSkWNIycxizBmKFPfrpa9ry2z4RAncGH7iqZrn3SDfNN+Ob74ElEaprbUFBIHs4uAiH/Tsy+c/xv7viikpWSsURyrmenxTfLoufrmBEvaQnnyHWK4bC89Lychk7/792B0O5s+fz6xZs3j22WcZ7eN5s6+6huefe46333+f117/b9C1SCie98ny5YDiGWdJSSE3JwdrUhLZWZnk5+eTZDIiebyaPDg1NZX8/PwjgudNnKLwvJ0heF5+fj75hYXk5uSQk5VFUlJSVKEbKo477jh+cf11/PKOO2lta8Pljp7nfbpiBfbOTh65f1HQOhM8L/6RKPIdpVDJQqginykpWesy1VfuUWLKBSEqAmjNzUUQRNxOh9bxTM0KX+QDv19LvHV4Vbmux+XE7XIGyDj9JCy7tAy9wYijs4PmCNLbJp9UNy0nD4PZjNGSpBHsnqa8ZFnWzJ7V9K9ACKJInVfpOmcFkPnUbCUBz+N0KqQmzhFInG2tLexZt0b7uywrcvJa5frvlM8psOrVl0Mu01y9n91r14AgYEpKxtHRzt6N64KW6erHp0KT7PaQpKzJdYsUjxzVszGaY2zvaMft9oAo4nK5cLlc2B1OzS/NlJoKOh1Oh4uGfXtxOh3acj/kFksBeMWKFYwf75eEi6LIFVdcwZIlS4KWe/nll5kyZQoDBgzgww8/pKmpievnzcNkSdYMhSW9iTNPP41B5eXaFF4oWHzJaU6nU5ti9Ho8YQudavqhwWzuJj37xS9+gSzLGsHYv38/M2bM4Pjjj2fdunU8/fTTPPfcczzwwANBz3vppZfIzs7m66+/5sYbb+T666/nkksuYfLkyXz77beceeaZXHnlldiiKNirmDNnDsXFxXzzzTesWbOG22+/HUMY0ubxSph8Mn2XK/h3UpFW+Dr9bv9+0et7JoCCKCLqRH7x0+vJycnh7vvu57cPP4IgCPz2t7/t8fkF+XnMuOASPvnwvaAJw0Bs3LiRVatWYfRNp65du5ZNmzbxy1/+EjGEuXR6enrQ3xMmTGDFihU9bksCCSQQjIYwyboqkrt819S00GgQNMknCJoCJBwyexGydqigynXVZlzXCS9QJKZa+EbYApA6yecv8gX6tUU619ZV+pJ1B4T24wP/8ezqyQf+JrxqCxOP6Gz2FfmsAUU+n2R37+aNEcM3VKnuoPFK0e7YGeeh0+s5sG0z+7duxtbWqhXyRp12pvY8dfnda1fj9Xio90l103PzQ4Zy5fmSlGvC+PJ1TdZVocqyI3kvupwO3G4PcgDHc7lc2J0+nufx4Ha7u3E0jyTjdntw2B04nc644nknTJhASVERy1esoLGxkV/96leA31POI0mcd8EFDCov543/+z+tmd0VKs9zu10YzRYEQUQURUxJipLH5gts8QduhPfi6788Tw7L8wB0XfyMdVGEbmjL6g1BPO+e3/wmZp736bL3cIcpNCd4Xnyi/zuSJ9ArBHq1dIUgCCRnZNBaW6P5lqVl54YNzwiETm8gLSeH1rpaDmxTxq4jyXVB6fDub7HTHGfkz2ixIOp0SF4vtpZmGn0j/oGTfDq9nrxBFezfupnq77eRWVgccl3+8BL/49a8fGytLbTUVJNXPijk8wDaGxuwtbYg6nRhDZkbffsuO9n/o683GEjNzKa9sZ7WulpNIhGvsPmKfIIgIssSG5cv0wjagKxkVlc2hzVl3v7l/7T/7920nqqN6ykdGSzjXvvBOwCUjx1PWnYu65a9y7YvV1I21k9m/Mm6wcejYPBQNn32MQcieC+67DZNoq76V0Zb5HO73TzxzLMRl+kr3HnnndqJuSdUVlZSWBhMbufMmcOjjz5KVVUVpaWlSJLEv/71L+6++24ArZs6uGIQpqQk9DZfQIRoQBRFKgYODOq4BsJms3H33Xej0+mYPHGi5v+ybPlyhSQEFPHuvPNObr3lFs3cOdTvVWZmZpCZ9FNPPUVJSQl/+ctfEASBYcOGceDAAW677TYWLVqkkZMxY8Zo7+eOO+7goYceIjs7m/nz5wOwaNEinn76adavX691v3tCVVUVt956K8OGKdPAgwd3L+Cr2H/gAIuf/TMFhYUMHTpUu/+2225Ttkv2BXMIAv/8+7NMmjgR0dfDmzx5cjeSZbfbGTt2rJa6pvdKPPHwQ5x13gVIsszKlSsxR5FKrBcFygYNprOjnYaGBvJ8id5vv/02KSkpeDwenE4noijyl7/8BYDvv1cuntT33RMKCwv57rvvolo2gQQS8COSYgP8k3wqAotTPUH1/AVISrP2aADv91+OL54Hfrmuiq6BDCryB1bQfGAftbt2MHDc8UGPOTo7sPsaTBlBnnyKlNNlt+Ho7NAUAoGQJK+W+JoTJlkXoFEr8vXTSb7WYLkuQIkvYbdmx3YGHK8UP7ryPFtriyYpHzjeH7h3zMmnseGTD/n6rdcoHTEayeshb2BFF0udoVjSrNjbWtm/dXNAenL3Qi5Ans8Sp9bHBbtC9dHu+l2x5uRRt3tnRO9FR2cnz/3r32EfB3gz4qO9R1/xvFtuvAGAnbsUufnw4cOBgCKfV0YQBIYMHsyOnTtxOxwYu3CLQJ43acIETMlKYe/tt9+m5KOPtAKlIAjceN0CfnH99RGLfP2W5+3fz+Jn/0x+QRieB9q+ePm5v3H2rPO0ZSLxPFBC/PR6PU888jDTz4+N5+kEgXIfz6urb6CoQPntT/C8+EeiyHeUoifyl5yeSWttDVW+Il9WUejiVSik5xfSWlerpUj1WOSL0w6vIAhYUtPobGlm35ZNeD0eTEnJ3bxoCgYPY//WzRzYvoURp5wecl1NXWScABl5BVRv39pjAUhN+soqGaBJELpCI39djqc1L89X5KuhcEh0P7aHC+ok35ATprDtixXs+vYbOluaSU7PoFxNXgsh1/W43excrXR58yuGULNjO6v+8zIlI0Zpk1wuh11JXQPGTZ+J3mBg3bJ32fH1KqZd+1PtAkWb5CsPJtpqwm7Njm1IkhdR7J4Qqk7xJVnTNSIfrVy3P8ipQSENXUnB2LFjGT58OEuWLOH222/ns88+o66ujksuuQQAjy/tVdTrFaIhKrJ2jyST4luXocsF4hVXXIFOp8Nut5OTk8Nzzz3H4IFl2NvaEHU6ppwwkYfu+w0ZBYVacltmZia2thYABFEIm+Iqy7L2udiyZQuTJk0KmvibMmUKHR0d7Nu3j9JSZSJz9Gh/wVin05GVlcWoUaO0+9TiVl1dz+l6Km655RauvfZa/vGPfzBt2jQuueQSBg0KLi4XFxcjyzI2m42hx4zk+X/8K4io33rrrcydO5fW+lpcNjsGs5msdKtiRu1WCqL//ve/NeKtYs6cOf73YzDgdjoZUlHBjLPOwu5yctxxx0X1HnSiAL7PbmDw2qmnnsrTTz9NZ2cnjz32GHq9nosuugiI/bNusVhi6pwnkEACCuojTH6BP11XRXoMct2UrCytCRopdEOFNskXZ4oN8E/yqegayKAib2AFW/73KbW7uheA1GTd5IxMLRwNwGBUrDZsrS201dWGLPI1Vx/A43JiMJk1b71Q8AdvhJjk8yXsNsZxkU9t5CYFFPmsefmkZGbR0dRIoVMpkO3uwvN2ffsNyDJ5AytIzfRfTxw38yI2LF/GrjVfa2oX1aNahSjqGHjs8Wz69CN2rvlKS2WNdIxBmdhz2mzaJJmKUNOaEN0kn3pNFO+IhefNnKHIptUCk3p+VxUbaliDoBMxGg24HXYgHejO8/74u99yzLBhmJKUovupp57KU089RUttDR6nE1GvIy0lBYPZovlWh0N/5nl//8eSkDzP43JpcvH8/LwguW5PPE8URUSdjqGDKzjn7Ok43J6oeZ4gCKh7LsHz+hcSRb6jFCr5C+fVkuI7CR/YuhmILnRDRXpeAZX4K/Jp2bkRl1flus1xSv46W5qp3LAWgJyy8m4SQNWXL1LCrjbJ5yNioBj3Qs8FoBqfH19+CD8+bf0q+UsOPvFZc/LZx8Z+Eb6hFvlKR42hrb6O6h3b2LJiOcfNvJCy7PAyjqoNa3HaOklOz2DmzXfw/E0L2L91E1Ub1jFg9FgANn++HJfdRkZBIWWjxyEja8S7auM6yseOx+1yasep6yRfdskADCYzLrudpv37QhLExhDeleokX2ttDbIkIYQYWwcQkZl3+WUIokDOAP9nrKnTyYEWB6lmPQN8UhaAjqZGOltaEEQlBVAfw9h+V4STDoRCdnY2zc3d/YjmzJmjkb8lS5Ywffp0srKUC78y31Tjnr37GDxqDHqdn/wZLRa+37mT0QFECuCxxx5j2rRpWK1WcnJykGVZMybXG02kpKRSPmAAltQ0reju9Xi01DxRCL2fGxsbqa+vp7w8vCQqFLruIzVRLPBvIMgsuSfce++9zJ49m3feeYf33nuPe+65h3/9619ccIE/LXzFihWkpaXRISYhGCyUZgZfcGRnZ1NRUUGbNQ1bWyuCICDLsvJ5cCsXMyUlJVRUBP92qNIYCJZ86PU69HL0nwdBENi9YzspqamkZ/jlesnJydprPv/884wZM0Yz8h4yZAgAW7duZdy4cT2+RlNTEzk5kS0fEkggge7osZkbMMlnSU3rNtEWCaKoIzU7h9baGlIyIkt1Ic4n+VL871tvMGrNua7QEnZ3dZdyhgrdUGHNzVOKfPV1IX2VVT++7NIBIRuIKlTFRleeB2hpwLbWFuwd7SGLiYcbHb5wtcDPiyAIFA8fydaVn2FpqgQKuk3yqX58A4+dEHR/ZmERg4+fxPdfr6KzuQm90cSwKSd3e91Bx01Uinyrv8TiSy4ON62ZlGYlNTuH9oZ66vbspOQYPzfxejxaWF5Gl0k3qy98ozVMAUiWZZAk5l1+GVklpUGhCe12N5VNNpKMOgbmhP4ONu3fh9vpxJqXF9P3VEVf8TxrWiqSx8vgIcqE2pYtW5g8ebKWDuvxJSVv/34HwwcPxu10aAWgQJ6XarHQUluNzmDQilfJyckMHjwYR2FB0HVSUlr4KT7ovzzPoUvGqzdTaLUErUPleZLXS53JoG2LLsCSpSeeB4rSTvJ6MRgMeGKcK9i9M8Hz+iMSnnxHKXokf74vsjqFE1ORL5AgCYK2rnCI10k+AIvvZFLlK/J1Lf6AIuUEaKiq7JYepaJrIAMoCW4ArT1N8kXw4wNwuL20OxWfhK4dXmue6gcTvrsYL+j0eW4kp2cw8tQzANj4qTKqH8mQefuXKwEYPHEyadk5jJmmdBZX/uefyLKMLMus/eBtAMaeda7iQybqGDxxCgDbvlB8IBqrKpElCUtqWrfJBFGn05KNwxVzQ01rpuXkIup0eNwuOlrCJ0d5XC4MBj1JySmYTCaMRiNGo1GRUhoMmAPuMxqNZOTlk5yail6nw9nWGvRYrLeuRetIGDduHJs3b+52/+zZs9m4cSNr1qzhtdde0zqIsixz4gkTyEhP56lnFTlyIPl7/6NP2LVnD5dccF5Q5y8/P5+KigrtpO+y25G8itmyzjcRCIo/i2pmbW9vQ5ZlRaYb5j09/vjjiKLI+eefDyjSki+++CLotVeuXElqairFxdFPL/cWQ4YM4eabb+bDDz/kwgsv5IUXXgh6vLy8nEGDBmG2KKReLZB2hTq1qHXRowjdUNE1oU0IUyANhbq6Ot598zVOPescZELvc1EUufPOO7n77rs1+cgxxxzDo48+GpIst/h+B1Rs3LgxKpKYQAIJBKPH4I0AX6RYpLoq1PCNqCb5kuOX5wVO8mUWl4QttOWWD1LCN5oatWA5FU0hQjdUaL58YcI36nwNrEihG+D35As1yWc0W0j1hdw1xakvnzrJl9xFJq6Gb7j2KcXTfc02XB7fxL/LxZ71SjKuGqIRiOPPu0j7/5CJk0MWwMpGjUNvMNJaV0vtToVPhwpXUaH68qmWQypa62qRJQm9ydQtTVqVr4fj2ipPMZqMWJKSgjiYaFB4XiSeZraYMRj06EUxbnje7NmzkTyKYmD69LPJzMzk0UcfBQI9+WTeeustduzYwWUXXYjX49EC7wJ5ntOmcHtzUnK3bVV84pXfD0EUMfVQ5Oy3PC9Z5Xmhj5Ugitq+0RkMMR1T5TnKXFcsHA8UnvfOG/9J8Lx+iF4V+T7//HNmzpxJYWEhgiDw5ptvBj0uyzKLFi2ioKAAi8XCtGnTNH22iqamJubMmUNaWhrp6enMmzePjo6OoGXWr1/PSSedhNlspqSkhIcffrg3m5tAF9hdXjp8RaHwct1gGUc0yboq0gMMaVPSM3r0aonnST5LilLkU6fMQpGwlMwsUrNykGWJmh3dO7xOm42OxgYgeD+qk3zNEYp8sixrcl21yNQVKmk26ATSzMH7Ol0lHv1hkk/1a7FmMHTySeiNJhr3VVGzY7s2ydfY6aLN4Q9c8Hrc7Fj9BQBDTjgRgAnnX4LeaKJ6+1b2rF1D1cZ1NO6rwmAyB8mph05Slt/5zZd4Pe4Aqe6gkCdPtZh7IEz4RqhCrqjTaZOskSY21XRDgyn4++hrgiJ2SVwTBIEUnwzefQglIGeddRabNm3q1uUtKytj8uTJzJs3D6/Xy6xZswClSWA2Gnn4gfv4v7ffYcGCBWzZvIH9e6v49z9fYv6CBfzo8ss47eSTNRIcCk5f4IYpWfkcuD0eWjo7qauvZ+e2rVRXV7Nvj3KhlGRVOvXt7e3U1NSwd+9ePv/8cxYsWMADDzzAgw8+qHUff/rTn7J3715uvPFGtm7dytKlS7nnnnu45ZZbQpoFHyzY7XZuuOEGPv30UyorK1m5ciXffPNNN7mFCrUbru/yOVDfY11jI3X19dTV19Pe3hGzIXMgwhFHWZapqamhurqaLVu28PzzzzN58mRS09L4xe334Ikgz7jkkkvQ6XQ8+eSTCILACy+8wPbt2znppJN499132bVrF+vXr+fBBx/kvPP8PjM2m401a9Zw5plnhl13AgkkEBqRAtZAKQzpfeecWJJ1VajTY+rEesRl45jnBRaGcsJMeIGyv4qHjQBg1X+CA77CyTjBH1ISLnlVneSL5Mfn9Hhpdyi8PZQnHwSEb+yvCruew4lOXwBcUpfrCzV8o2HX92SKLiQZ9jYr0r29m9bjcTpJycoOyb8LKoYycPwERJ2ecdNnhnxdg9lM6agxAMiyhM5giPh5Lx+n+DSveedNLewLgkM3up4n03yTfOHkuqpU12A0dXuu16eBDJWsq0L0nae9hyBhN1qed+4552iPpaal8cwzz7B06VKF523cyP69Vbz68kvMnTuX+fPnM336WQC4usgyZVnWinwqxwMlbK2mpoba2lraXW7q6uuxuz1B3OzI4nm+Jm2XZq76Hmtra6lvbKKuvp5OuyPm7VEVP0KEz1l4nmdVeJ6U4Hn9Cb36dHd2djJmzBiefPLJkI8//PDDPPHEE/z1r3/lq6++Ijk5mbPOOguHw/+hnDNnDps2bWLZsmW8/fbb2pdTRVtbG2eeeSYDBgxgzZo1PPLII9x77708++zhMac/kqB2A016kRRT6AJc1+k7NUggGmQETPL1lKwLfhmHKjmNJ5hTgyUPuWECMgqGqJLd7gWgpgNK8Sc5PSNIFqJOPHY0NoQt1LTW1eLo7ECn14c1CvZLdbuTB2ueUuRrCdNBjhfIkqSlZyWlZ2BKSmbIxMkAbFy+jBSTXrtQCZzmq9qwDmdnJ0nWdIqGHQMo+3nsWQr5WPnqy3z3/v8BcMwpp2NK8hOIomHHkGRNx9HZQdWGdf705DDd9IIhyok51DEG/yRfVpfvinYMIhRz1cQxfZewCMlXOAnV2FOL55LHiyxHLx/4IRg1ahTHHnssr776arfH5syZw7p167jgggs0mYBK5i668EKWL19OVVUVZ552KjMmj+HXv7qR2267jSf+qHR+w03ByrKsEW1zsvJ9fP/99xk+ZhxjJk1h2OgxFBYWcu7FlyDqdNoFm9poqqio4Morr6S1tZWPP/6Y2267TVt3UVER7777Ll9//TVjxozhuuuuY968eZrJ8Q9BWVkZ9957b8jHdDodjY2NXHXVVQwZMoRLL72Us88+m9/85jfdlpUkGa/vc2Do8kFQ3+OgIUMZM2kKYyZN4f6HH+7RryZoWwLlKBEIb1tbGwUFBRQVFTFp0iSeeeYZrr76av7vk5Xk5OVrFyqhoNfrueGGG3j44Yfp7OxkwoQJrF69moqKCubPn8/w4cOZNWsWmzZt4k9/+pP2vKVLl1JaWspJJ50U9ftJIIEEwOby9NjMBf9UVW8m+U648HJOnfsTRk+b3uOy8azYCJzkC+fVpuLkH10DwKbPPqZmx3btfi2QIURCsTrxGK4ApFpRRErWVfebXhRIM4ee1Fa5RzyGb0heLzZfMElXeXdmYTEZBYV43S7OO/AmyZ5OKn3WLFqq7rETwjagZt58BwueeoH8iiFhXz9wCjCzqCSsZy/AyKlnkFVcir29jS9ff0W7P1zoBviPsbOzM6gwqEIt8ulN3c/NklrkizCZpfK9Q1Hki5bnmXyKAVGvRxAELr74Yo3nnXbqKcyYPIZ7b/05CxfexrPPPovJotiNqAF1KtwOh0+pIWII8LN8//33KSgooKCggIEVgxkzaQrTA8Im4MjheeBv5hrE0DyvoKCAURMmMmbSFO6LIhW3K5Ks6aRm50Tkh+F43rvLVyV4Xj9Erzz5zj77bM4+++yQj8myzJ/+9CfuvvturVK7ePFi8vLyePPNN7n88svZsmUL77//Pt98841m/PjnP/+ZGTNm8Ic//IHCwkJefvllXC4Xzz//PEajkREjRrB27Vr++Mc/BhUDE4gddQFS3XAnzZSATltgkEA0sObmK3I5We4xdAP8/iLx2OENTHDSGQxh03MLBw9l+xcrqN7RXcqpBjJ0lTxbUtMwWpJw2W201dUG+fWpqNmpkMicAeXdJm5UNHSqEo7uP9yqhKCjsRGvxx12HYcbjs4OJK9CXtTEv5GnnsHmFcvZuuozpl59LeVZydS3O9nd0MnoYmWZbb5U3cETpwRJbI6fdRHrPnyX2l3fU6s0yRl31rlBrymKOoacMIW1H7zDti/+pxHjsEU+H4Fs3L8Xp60zqGDocbtpqVEKqV2nXtPzC6lc/13YST5ZlvH4inzdJ/lk37Z2/56KOp3mwSZ5vOgMh8Z9YdGiRdx6663Mnz8/qAt6/fXXc/311wct6/QV+YxJyZx00km8//77SLLMmp21/GLeHF566SUuu+gCzIKA224Da3o3w16Xwy/VNVosvPjii7z44ouAMh0ZSKiT0qwIoqilqkWDU045ha+//jrs459++mm3+0KtP3C7bTYbtbW1TJ06NeQ6jUYjr7zySsjHAKZOnaqtz+WTw4iCgBjwex24DW6HQ5skVb1aysrKwpofB74nUadDEEVkSeKpx/8U8jdu7ty5zJ07N+S6Khs7abW7tc+qemy64vbbb+f222/X/h4yZAgvvfRSyGVVPP744yxatCjiMgkkkEB3NLQrfCpSMxdQfPXqamNq5KpITs/g2LNDT091hX+Sz93Dkocegc3Xnop8BRVDOeakU9m8YjnLX/obl9+nKIwiTfKpoQyhklc7W5oVpYggRJwiVJu5mcnGkHwA/ByzMQ7lurbWFpBlBFHs1jwXBIHzFy7iPw/cDY0NXFT9Jjt2DeTUobmaH9+g8RNCrFWB3mBA32U6sCsC/fx6OsaiTsfUK+fx+u/u4bv332b0tLPJLCyOeIwNZrOW4ttWX9dNNux2+oq0IcLz1CZeuOMKSiEN0HhyXyManufoVAqxuoCCqcrzAL7dVcsN18zmpZdeYt68H5OdnYXH7cLR0UH1zu3+wqhvis9o8Ut1A3leOBxJPC+wmRso1+26DSrnVSdHo+V5oHyuk63pvPTS4pDLR+J5B1rsNHQ48fqktwme1z9w0K8Kd+/eTU1NDdOmTdPus1qtTJw4kS++UGR1X3zxBenp6UHJLtOmTUMURb766ittmZNPPjkoYeass85i27ZtIQ1BVTidTtra2oJuCQSjJz8+CJ7ky4whWRdAbzRqCViqR0gkxHOH1xLU4S0LKz0OlHJ2/cFt3KdIJ7oW+QRB0Kb5msMUgHry4wNoaA/v05JkTUdvNCHLEm0N9d0ejxeocmhzSqrmEVY8fCTWvHxcdjvff7WKAVm+hN0GpXDk9XjY+c2XAAw9YUrQ+pLSrIyb7i/qlY4a223CDvwS3x2rv6DeF9oQblozOT1Dkd3IMtUBHXxQCL4sSxgtSd2mYNPVSb4wx9jjciHLMqIoBk1VQeAkX3fyJwiCRvy8h4j4AZxzzjksWLCA/fv397is1+fpGVi8FAWBpCQLjz/3MlfM+RFffbMGUIp5ociKs8Mv1e3alAja14LfQ/NwY/ny5Zx22mlhyV8scKsSDlEI25QR9X6SrTPE5r8jCIL2uetNE0CVEEfq8PYGDQ0NXHjhhVxxxRUHdb0JJHA0oL5DUc5EauYCTL3yWk68/CoGjju+T7cnM1n5bWnsiL+EUdWWBcIHMgTixNlXozeZOLB9C1tXfY6ttQWX3Y4giNrkfiC0UIb62m7nOFWqm1FQhKFLomnQchH8+FRoRb44nORTOV6SNT2k52FmYTGX3/t75NQsrJ42Wv/zGFtXfU5HUyMGk5mSEaO7PScWpGRkapN+kYqpKsrGjmfgsccjeb189o/ngMjhKhAYvhGsnJFl2S/XNXU/flIUcl2d7tBN8kF0PE8tOIq6MIqwpCQef+5lLp/9Iz7//HPl+5GbrwxPyErR29bWGlKq2x9wUHmer3jWtZnbFSmZWaRkZnVLBO9r6BI8r1/ioBf5anzTLGrUtIq8vDztsZqaGnJzgxNX9Xo9mZmZQcuEWkfga4TC7373O6xWq3YrKYm9O3mko6dkXQi+eI7Fj0+FWryKRq4bzx1eNYkLILc8vF9Kbtkg9CYT9rZWtv7v06DHGsPIOCEwfTVMkc/nx5c3KEKyrq84GsqnRRAEvx9MHPvyqQQw0AtSEEVGnqI0C9Z//IG/yOeTcezduA5HZ4ci1R0+ots6j5t5IUafbDScV0vRsGNITs/A2dmJx+XEYDKHlNv4l1deZ807bwaR9UCpbtcLKtWjMpxcV/Xj05ti92pRiZ90iIifiptuuqnH31ZZlpG8yhSargsJ1IsiJrOZm3+5kEsvvxxBFJG8kkaEA9fhl+p2N1s2mEzaFIY5OSVuJlXPOecc3nnnnYOyLo+P/IUL3YBgkh1L6Ib2HL1a5It9uL+vyF92djYLFy6M2Vw6gQQSiK6ZC0pi7MQLLu3Vdz8WqM3cNocHt/fQ2EtEC4PZzImXX8WUS38UVYhIamY2E8+7BIDPX35B8/NNy83tFmQEkJqdC4KAx+nE3h48eKCFbkSQ6oJ/ki+cHx/4uXp7Q31Y+4vDhUDP5XCw5uZRNOdXNBkyEG2tvPvEIwAMGD0uJguKcDj16gWMmDqNUaedFdXyp1w5D1GnY9e337Bn7ZqI4SoAaT7lTNdQFsnrUbiQ4PdFC4SvjxexuOO3Z/GEndw62OiJ56m8M7DJGAi9TsBkNvOLX/6Kiy5SAlIEQSAtJ1fzTm6rr8PjciEIgibn7S84qDzP65/ii8R59EYjKRmZfeolGAoqz4vkydcbJHhe3+KIS9e94447aG1t1W5798ZfR+twoyEK8mdJSdUuHGNJ1lVx7NmzKDlmFIMnTupx2Qxfh7fF5jroF4o/FIHdklDJuir0RiMnXHAZAMsX/x17R7v2mFYACrEfI03yyZJE7W5lki8/wiSf2hnPDlO01Yp8cezLp6WuBaT9geKjJwgi+7duwvzFq4iyVyvybVNTdSdMCtkZtqSmccFt93DGghvDSj0CU3ZBkUVH8iVTL4b2rF3DtlWfa/er8phQ35XASb5Q5Mwv1e3exddkHGEnuA5tdzcWSF6v9n5Ffdcin0oYJARB0IqxLbU1QQEcwVLd0AQwLTtXC785EuEJmOQLB0EQNI+hUBcRPcGSZsVosfSqO6zzfV/U7Uwggb5GQrHRM+rV0I0IzdxDCavFoIWet8RhQ3fiBZdywkWXR738+JkXkJaTS0djA8tf+hsQvvijNxg0H7quPGzflo1AZD8+6JnngcJ5VLsT1SYmXtDpU2AlZ0SW1Q4qK+L1gvNosfjP56FSdXuDwiHDmH79TUHy7EjILCzWFCGfvPiMFqDX8yRfsCxbk+oajCH5pX+SL/y2qBwqsHl6uBGuiatCH6YwJAgCqVk5QU19g9kS0SfxSIfWzD3Exbto0VfN3AT6Fgf905Sfr1zQ1tYG/8jV1tZqj+Xn51NXF9zp8Hg8NDU1BS0Tah2BrxEKJpOJtLS0oFsCwdAm+SIU+QRRJCVTISVZRd294npCxfEncOk9v9OSRSNB7fBKMrTZ44v8WVIDi3zhJ/kAjpt5gWLW29bK5/98HlCkmK2+z23IAlB++Em+5poDuOx29AZjSL8+Ff7gjdAX96p8JJQfTLzAL+UIJoBp2TmcseAGBFGkdf0XzKp5h/21TXg9HnZ8E5yqGwrFw0cy+vSzInaJhgY8P9K0Jiikb6JazH3pbzh8UtLGCIVcdf+77LZuXXwIn6wLoCbPh53k0x+eSb5ooEk59Lpu+1/1HFHJX2pmNjqDAa/bTdOBfdoUgibVTeou1VUh6nSkZGT2+STK4YIq1+0autEV6vvvzcSDKSmJzMLiXj1X3a54m85J4MhFQrHRM6Kd5DtU0OtErBaloRuP/suxwmA0cfIcJYSj+YBSUIukAlCbrYFTXlUb17P7u9UIgthjIUtVbITjeSq0hN198ZWwG0qtEQpl2Uk4dBb+kzuT4hGjScvJo+K4Ew7FJobECRddgSU1jWbfFJ85JTXIqzsQ/hRlP9eWZVnxIyS0GgECvJcj8FTFaze++J63B7muqj4I1QBUCn3ZpGRmIYgiSQGqqaMRnih53uGCwVd8dCeauf0KB73IV15eTn5+Ph9//LF2X1tbG1999RWTJilTXZMmTaKlpYU1a9Zoy3zyySdIksTEiRO1ZT7//HPcbn/RZ9myZQwdOpSMHjpBCUSGSv4idQQBTrziasaccTYlI0b16fYYdCKpZuUk0RRn5E+V6wqCSM6AsojL6vQGzlhwI6Akwu7dvEHzajMlJ4ckN6pcN5RfmyrVzSkfGLHDdaBVKYjkpYX2c0n3SQjiWq7rI0Gh9tGo087kgoWL0JvMlDj2M23nq6z5aBmOjnYsaVaKh4/8Qa9dOGy4Jk+PNK2p4vjzLiazsBhbawsrlrwIBMp1uxdjDUaTJgHqepxlSdIm17om60LP5E8lV4fSky9aqNOFobq8Xcmf3mgks7AYg8mM5PXSfGA/9o52v1Q3ys77kYho5LqgWCxYUtMwJh1aXxuDb7tUT5kEEuhrJBQbPSNanncooVqzxKP/cm8w5IQTNQsPCD/hBZCWExy+IXm9LH/xGQDGnHl2j2EQB1oi8zwV8erLF22RLyfFRLJRh0M0cexPbufaP//9sJ7/zckpTLnsR9rf0RzjwEKuy27zhd7pSQrz3lXFRiRPPog/5YY6yRdWrhug2AiHlIxMcssGHtUcD4K9l+MRgc3cQyUXT+CHo1dFvo6ODtauXcvatWsBJWxj7dq1VFVVIQgCN910Ew888ABvvfUWGzZs4KqrrqKwsJDzzz8fgOHDhzN9+nTmz5/P119/zcqVK7nhhhu4/PLLKSxUfkBnz56N0Whk3rx5bNq0iX//+988/vjj3HLLLQfljR/NiLbDO3zKKUy79meHZIQ6Xslfel4Bo6dNZ8rlV4aUU3ZF0dDhjJ42HYBlf3tS82rJLOru1Qb+Sb62hrpuJ+4aX5Evf1B4qS7A3iaF/JVmhZYzqpNkLXEs1+1sbgLCE8Dyccdx+W9+j12fTJa7mRUvPAn4pLo/8PMpijpOv+Y6hk05haGTe45w1xsMnDH/BgDWf/y+VsyF8NL2cBObHrdbCd3Q6UJOomnBG2F+qXU+cuX1xId8IxB+AhiiyBeC/On0ejIKizAlJyPLMq21NT6prhhWqns0IBq5LigXI9bcvEPu1aIV+bxygvwlcEiQUGz0jHib5API9Kk2muOM5/UWgiBw6tXzUXXIESf5fFLONt+U19oP36FhbyXm1DQmX/qjsM9TsbdJCRwLx/NUZJUojcZ4m+SzRVnkEwSBsmylUVXZaI8Lr65Rp52lBbJEM63ZWqcErHQ0N+K0KcctJSs77LlZimKSD/zT+vHS1NU8+XqS6/Yw/RUPx/hwI9pm7uGCyvMkWU5IdvsRevVpWr16NePGjWPcuHEA3HLLLYwbN06LQF64cCE33ngjCxYs4Pjjj6ejo4P3338fc0By1Msvv8ywYcM4/fTTmTFjBieeeCLPPvus9rjVauXDDz9k9+7djB8/nl/+8pcsWrSIBQsW/JD3mwDxSf7iNWFXEATOmH8DE8+/JOrnnDR7LsnpGTQf2KdNeoULL0lJz0RvMCJ5vbQHpN96PW52r1UmXfPKw4duuDySNslXmhmmyKd2F/uBXDcSAcwrH8TWCdfQYPCHwkSS6saCwRMnc87Pb8VotkS1fPExIxl56pkAvPP4w3jdbvQGI2k5oX3h1InNrt6LLrtCAEOFbkiyrBX5evLkk+KE9AVCijTJF4b8iaJIel6B5isEYEpKOapJoEr+DHFK/lTptSzLB92UOYEEEugdorFlOdTIUJu5cabY+CHIG1jB1CvnMWTSSRRHSIBN06ScddhaW1j16ssAnHjZlVii8EKtUot8YXieCnUisKGqMqrtP1ToiLLIB1CWpRT5VP/lww1Rp2P6T29mwOhxjD3r3LDLqfZEbocdR0c737z1X5BlDCZzWKkuRD/J5w9aO/y2RsHBauGCN3yKjQQv6BGBwRvxCFEUNL/AhGS3/6BXJkZTp06N2LEXBIH77ruP++67L+wymZmZLFmyJOLrjB49mhUrVvRmExMIA1mWo0rXPdRQfUaOhA6vOTmFU+cu4O0//V4rXoUr8gmiiDUvn8Z9VbTUVmsTX1+98R+aq/djSbMyaHx4r5b9LXZkGZKMuvCefD65rqOzA0dHR1yOxWuefD0QwKKiQl7ffz4/0X1LRZaFkmP6VkoeCSf/6Bp2ffu1tu0ZRcUhA0AgdIqy1+PB3t6GXhRJCuHxIgUQo2jSdWVZjqtimFdLXosg1w1B/lSvFr3BgL29LajgdzQi3mUcoiBg0Im4vRJurxS3xcgEEjia0BCPct0jbJJPxfhzzmd8D8tYA+S6K15ZjNPWSW7ZIEadfmaP629zuGn2hZWURFnka6uvxWW3xc0UvC1KjgeKLx/A7ob4KPKB0mS++K77Iy6jNxpJzsiks7mJjZ9+xJ61a8gcPprkjMyw3EyW5R69l1WIesXTMh7kupIUGKzWg1w34dfbI1S7E0OcBm+AItn1SIpk18LRG5LSnxC/n6YE+gQNHS5cHglR6Nnb41DiSOvwDjnhRMrHHaf9nVkc3hhcLeypfm0Neyv56o1XATjtmp9ELMoFdnfDkQiD2awVSuI1YTeSJ18gyrKTcYkmqsZcxHm/uuuwpnFZUlKZetW12t/hCrkQkKLsK/JJkhdHRzuyLGNKSsYUossbmKwbNnQiDhPXVKiSksiTfKHJnyAIJFnTySouDRlIcrRAkmVtHxn08Xu6DpTsJpBAAocXHq9ETZsS6FScEd10+qGAyvMaj7AiXzRQpZwtNQfY+OkyQOF34RqDgVClulnJRlJMkWczLKlpmsdww974kexG68kH8TfJFwvSfLLs/72yGACjxYIhQqCVJINMtHJd1Z4lDop8PosYUadDEEJzE0NAwFrCyiMy3J74Dt6AQJ6XKNr2F8TvVUMCfYJ9zQpZyE8zY4yji8bMI2iSD5Qixek/vh69yYSo05EzoDzsslr4Rm01kuTlw2eeQPJ6GDh+AkMnRfaIU4t8PXV3Q6V+xQu8HjcOX+psTwSw3Nfh3RMnHd5hU05hwGjFtiBvYHhZtX+STymybvnf53jdbgRRJC0nJ2QRT53ki9TdFQThkEt2Gxsbyc3NZc+ePRGX0/xaQnR5E+QvOri9EjLKcY7XST7ou4Tdv/71r8ycOfOgrjOBBI50VLc68EoyRp0YV4qNzGRfuu4RwvNiQUpmNoIgIksSyDLDTzqVomHHRPXcvVHyPBWaZHdvfEh2XXYbbqdSdI6myFfu8+Tb02Dr0+3qC6gTm5LXgzEpGVMPQViqJYsA9HSKVyf5DkW6bk88T9KSdcMXqVV5Z6D1TALd4ZVkvy1LHF2Xd0VfNXMTPK/vEL+fpgT6BHubFf+24oz4GOFX4ffkO/xeEwcL1tw8Zj/wKJfc/SCpmdlhlwss8q394F2qv9+G0WJh2ryf9ii/3BulT4s1jhN2ba2tgCJd7smbRjVk3tMYH+RPEARm3XIH5/xiIWPPPCfscuokn621hYa9lXz7zhsAJFsz0PmIW1eo9ZIeu7u6Q5u49uCDD3LeeedRVlYWcTmNBPqKkKtWrWLGjBlkZGSQlpLMRdMm8+Izf8HdZbsF3+SiIAhYrVamTJnCJ598oj0+d+7coGXU2/Tp07VlysrKtPstFgtlZWVceumlQeuJZ3z66acIgoDZoGdMSQanjh3MxRdfzK5du7RlAt9j4O2hhx4CYM+ePQiCoAVkBWLq1KncdNNNOJ1ORowYEdLrduHChZSXl9Pe3s6LL76orV+n05GRkcHEiRO57777aG1tDerwBh4fg8FAeXk5CxcuxOFwBK0/cJvT0tI4/vjjWbp0adAyP/7xj/n2228Tth0JJBAD9vqauUUZFsQ4ag5oPM925PC8aKHT60nNVnigwWzh5Nlzo35utH58KvxFvj0xbWNfQZ3iM5gtUfkeqzzvQKsdhzu+FAo9QW2oA4yfMQuhB/mlGmIgiuEVGyp0Aem6fd0c7YnnhQtWC+R5SUkWLpo2hcXPPonTleB5XaHyPL1OVHjeuCFcdsklcczz/M3cBM/rH0gU+Y4yqJN88SThgIAO7xEi11WRU1pG8TEjIy6jFoBqd37P/155CYCTZl9Dalb4wqCKqsboyF+6L2E3HuW6mozDmt4jIRqQqZC/Vrs7bqYBjJYkhk0+GX0ESYYpKRmLz3fvrT/+Do/Lhc5giCjFlqI1Y9b7ffn6Gjabjeeee4558+ZFXE6SJCRflVKn0/PGG29wyimnUFxczPLly9m6dSs/mnc9f3viD1xx+RXdCOsLL7xAdXU1K1euJDs7m3PPPTeI+EyfPp3q6uqg2yuvvBK0jvvuu4/q6mq2bdvG4sWLSU9PZ9q0aTz44IMHaW/0Pb76bgMfrd7Ck8/9g02bNjFz5ky8AbJs9T0G3m688cao128ymVi8eDEvvvgiH3zwgXb/l19+yWOPPcaLL75IaqpSeE9LS6O6upp9+/axatUqFixYwOLFixk7diyNvt8VVXKiHp9du3bx2GOP8cwzz3DPPfd0e331OK9evZopU6Zw8cUXs2HDBu1xo9HI7NmzeeKJJ2LbcQkkcBRjn9bMjS+el5VyZCk2YoVafDvhwstIycyK+nm9LfI1xskkn1+qmx7V8lnJRlJNemTZ38juL8jy7fvcskEMmdRzMJzG86LwU1akscpyfcn3ouF5Xi1YzT/JF4rnXTX/Ov72xB+YM2d2gueFwZp1G/lo9Rb+/LfFcc3zGup9PM/H7RM8L/6RKPIdZYhX8qd2eI9GrxZ1kq+juQm300HRsBGMmTa9h2cpiJb8qZN8LXE4yRdt6AaAxaijwKp4Se7uZ34tWsLugX2Iej2W1NSInVutw9ujhOPQ+bS8++67mEwmTjjhBEAp5hUXF/P0008HLbdm9WoKBw9lX/UBbHY78+fPZ9asWTz77LOMHTuWsrIyLrvyau5/7Cn++9/XefXVV4Oen56eTn5+PiNHjuTpp5/GbrezbNky7XGTyUR+fn7QLSMj+POTmppKfn4+paWlnHzyyTz77LP8+te/ZtGiRWzbtk1b7rPPPmPChAmYTCYKCgq4/fbb8QTsy6lTp3LjjTdy0003kZGRQV5eHn/729/o7OzkmmuuITU1lYqKCt57772Y9uW6des49dRTSU1NJS0tjfHjx7N69eqgZawZ2eTk5TPlpJNYtGgRmzdvZseOHd3eY+AtOTmyPKgrxo8fz1133cW8efNoaWnB4XBwzTXXcOONN3LKKadoywmCQH5+PgUFBQwfPpx58+axatUqOjo6uH/RXYCf/KnHp6SkhPPPP59p06YFHT8V6nEeMmQI999/Px6Ph+XLlwctM3PmTN566y3sdntM7yuBBI5WxDvPazoKeR7A6T++nnNvup3jZ14Y0/OqmpTjGXWRr7QMiB9Pvs6WFgCS0zOjWl4QBG2aL57CN6LB0BNO5Oyf3cJFd/4mKr/FwEm+nhBoz+LtQ3uWaHie5PWyYdNmMvILqayspLOzMyTPu+LKa7j/sad4M8HzwvK89EyF500+Mb553n133wn45boJnhf/SBT5jjJo5C9KsnCocKR58sWCtJxczddCZzBw5k9u7HGiDZSwhWi9WlQJQVscevLFYsgMMCArvnz5ooU6sQkw9sxzEAMCKWRZxuu1Bd1cnk5kyY4g27s9FnhDcCNJDtzu9ojLhbvFIvtYsWIF48f7cwRFUeSKK67olpS+ZMnLHD/+WMpKB7Bs2TIaGxv51a9+FbSMXhSZesbZVAwe3K07GwiLRblQdbl++G/DL37xC2RZ1uQC+/fvZ8aMGRx//PGsW7eOp59+mueee44HHngg6HkvvfQS2dnZfP3119x4441cf/31XHLJJUyePJlvv/2WM888kyuvvBKbLfqpgzlz5lBcXMw333zDmjVruP322zEYgqXbauKaUS8e1P3QFXfddRf5+fn8/Oc/5+6770YQBH7729/2+Lzc3FzmzJnD++++jdfrDenJt3HjRlatWoUxwqSrx+PhueeeA+i23HHHHYfH4+Grr76K8V0lkMDRCb9iI0553hGm2IgWaTm5DJ10YlT8LhCxevJlFZeAIGBrbcHmCzU7nOhsaQKi53gQwPP6WTNX1Ok45uTTtLC7QITieW53dDyvK99zOWPjeweb50leD/996y1OOGEiAwYM4MMPPwzD8wSmnnE2gyoSPC8cz3N5+wfPe/edBM/rb4gc05TAEYf4lesevUU+UacjPb+Qpv17mXTRFWQWFkf1vBabm3an0onq6XhaNbluHZLkjarDeKhgi7HIV56dzJe7mvpdkS/Tl76bM6CckaeeQdXevdpjkmTn089GhXxeA7Ar5CMHB1NP2YBOF93FQ2VlJYWFhUH3zZkzh0cffZSqqipKS0uRJIlX//MaP7/uJ4h6Pdu3bwdg+PDhQc9TgyQqBg/VlukKm83G3XffjU6nC+o2vv3226R0kTrfeeed3HnnnRG3PzMzM8hM+qmnnqKkpIS//OUvCILAsGHDOHDgALfddhuLFi1C9F2MjRkzhrvvvhuAO+64g4ceeojs7Gzmz58PwKJFi3j66adZv3691v3uCVVVVdx6660MGzYMgMGDB3dbxu2R0Bmgqa6WP/zhDxQVFTF06FDt8dtuu03bLhXvvfceJ53kD+yZPHmy9j5U2O12xo4dq/2t1+tZvHgx48ePR5IkVq5cidkcXfr6sGHDaG9vp6W5Cb0vWVA9Ph6PB6fTiSiK/OUvf+n23CuuuAKdTofdbkeSJM1TJxBJSUlYrVYqK+NDepZAAvGOuJ3k8/E8m8uLw+3FbIgfHhKv8EqyxttLs6I7TxtMZtLz8mmpqaZhbyWlIQpOhxKxNnLBH76xux+Gb4RDJJ4HENPc5d6eFwnEweZ5HpebpW+/wx133A4Qnuf5fNwqhiR4HoTmeS6vBDpoqu8fPC8rOwdJlhM8rx8gUeQ7iiDLMvt95K8kTju87U4PLo8UV8m/hwJnLriRmp3bGXvWuVE/R5Xq5qeZeyTLKZlZiDo9ktdDR1Mjadm5P2h7DyY6W2MjgGVZPvIXJ+Eb0WLMmTOQvB5GTj1D89Hrb7Db7d1IwdixYxk+fDhLlizh9ttv57PPPqO+vp6ZZ0/XQkGAbp1klfzJdO/qBZKCnJwcnnvuOUaPHq09fuqpp3aTCGdmRicFkmVZk0lv2bKFSZMmBcmmp0yZQkdHB/v27aO0tBQg6LV1Oh1ZWVmMGuUn63l5yqRsXV1dVNsAcMstt3Dttdfyj3/8g2nTpnHJJZcwaNCgoGWmjB2GLMs47DbGjBnD66+/HrSvbr31VubOnRv0nKKioqC///3vf3cj3nPmzOm2PccccwwXXXQRLS0tHHfccVG/D/W4ioKA7EvRU49PZ2cnjz32GHq9nosuuqjbcx977DGmTZvGrl27uPnmm3niiSdCHkeLxRJT9zyBBI5m7I/TgLVUkx69KOCRZJptLgqs8VWEjEfUtDlwe2UMOoH8tOguyEHx5Wupqaahag+lI8f04Rb2jN4U+VSe19+auUcCouF5K1aupKGpiYsvujhoue48T9TuT/C80Dxv0qihSP2E5xl8qjNZJsHz+gH655VmAr1CfYcTp0dCFCDfGj1ZOBRIMxsQBZBkaLG5yI2BzBwJKBp2DEXDjonpOZUxmDGLoo60nBxaaqpprauNryKf6slnjbLIl90/yZ8lJZXJlygn3a4JVKJoYeopG4LuO9Bso8nmJjfVFPH74HG7aNy7F0EUyBlQ3mNCW1eIYvQXWtnZ2TQ3N3e7f86cORr5W7JkCdNOO43MjAxEvV7rXG7ZsoXJkydrz1HJ3/ZtWznu2HFB61NJgdVqJScnp9vrJScnU1FREfV2q2hsbKS+vp7y8vKYntdVXqEmigX+DYp3TbS49957mT17Nu+88w7vvfce99xzD//617+44IILtGVeeP1dUlJSmTRyIJnp1m7ryM7O7nE/lJSUdFtGlYR0hV6vRx9jAXrLli2kpaWRnZ2NV1aMxAOPz/PPP8+YMWNCGnnn5+dTUVFBRUUFL7zwAjNmzGDz5s3k5gb/PjU1NYX8HCSQQALBcHslqlvVZm58FdEEQSAj2Uh9u5PGjkSRLxpU+uSqxRlJPYZwBSK7ZAA7vvmShjgI34hVrQEBPK+fyXUjIRTPq2tzUNfuJDPJQGEURXlbayvtjQ2YkpO1QL1oXzta9MTzbrvtNl5/801OPekkcvKUc3U4nmfwfWa/37aN48YneF4onrf4jXcxJ6Vy/PBycrPSu60jnnheTnYWTq+c4Hn9BEfXuNRRDlXCUWC1YNDF16EXRcFvynyU+rXEilh9WtTwjdY4C99QTZlTMqKX64JS5IvFZySeoUTWJwXdZDEJQbSg1yd3eyzwZjCmIYpmBEyIgjnisqFusRQFx40bx+bNm7vdP3v2bDZu3MiaNWt47bXXuPiC8wEQ9XrOOussMjMzefTRR4OeYxAFPv3wXXbv3NGtS6mSgoN9wn/88ccRRZHzz1e2b/jw4XzxxRdBn6OVK1eSmppKcXF0svkfgiFDhnDzzTfz4YcfcuGFF/LCCy8EPV5UMoAB5QPJsKb1+bb0BnV1dSxZsoTzzz8fk8GX8tzlKymKInfeeSd33313RFPlCRMmMH78+G6peDt37sThcDBu3Lgwz0wggQRU1LQ6kGTF3yk7xXS4N6cbMpOObl++WBErz1OhhW9UHf4iX8cPkOtWtzqwu7w9LN0/EJLnCRaF5xki8zyN75lSEUUzSIbDxvNWf/MNb7/3PheeN1Pzlg7H8/Qqz9uV4HnheF5e0QBKysrJyuhHPK8L0UvwvPhEfFV6EuhTqGShKM66uypUv5ajNXktVlQ1Rj/JB2hdv5ba6j7bpt7AFkO6LijvVxAUaXd9h7MvN+2wQj2J9lSPF0VRC27p64Tds846i02bNnXr8paVlTF58mTmzZuH1+vlzNNPB0Cn05OcnMwzzzzD0qVLWbBgAevXr2fPnj0s+ceL/PqWn3HZj+YyY8aMmLbD6XRSU1MTdGtoaAhapr29nZqaGvbu3cvnn3/OggULeOCBB3jwwQe17uNPf/pT9u7dy4033sjWrVtZunQp99xzD7fccks3f5ODCbvdzg033MCnn35KZWUlK1eu5JtvvukmtwAw6MSwBF19j4G3tra2PtlmWZapqamhurqaLVu28PzzzzN58mSsVisPPfQQBp3a5e5eeL/kkkvQ6XQ8+eSTEV/jpptu4plnnmH//v3afStWrGDgwIHdJC4JJJBAd6g8rzjdElVi56FGZoLnxYQqTbERG2/PLhkAQMO+KuQYJo/6ArFyPICMJANpZqWg0N8SdmOBxvOiLMLptHRdd59tU08879r58/F6vZx1xhkaTwrH815erPC8S+ZcneB5EXieThTQhdmW+OJ5yjaGoHkJnheHSBT5jiLEqxmzCrXDmyB/0UEjf1nRHU81+KFhb0z2vn2OWP1azAYd5T6/li3V7X22XYcb3hjIn9pNlbx9W+QbNWoUxx57LK+++mq3x+bMmcO6deu44IILtG6fqFeKjxdffDHLly+nqqqKk046ifLycn7+0+v48c9u4t5HHo95O95//30KCgqCbieeeGLQMosWLaKgoICKigquvPJKWltb+fjjj7ntttu0ZYqKinj33Xf5+uuvGTNmDNdddx3z5s3rZnLcG5SVlXHvvfeGfEyn09HY2MhVV13FkCFDuPTSSzn77LP5zW9+023ZSP6k6nsMvC1cuPAHb3sotLW1UVBQQFFREZMmTeKZZ57h6quv5rvvvqOgoEAjf6GGa/V6PTfccAMPP/wwnZ3hL9imT59OeXl5UJf3lVde0YyvE0gggchQeV68NnOP5pC13qCqSTme0TZzVaTnF6LT63E77LQ11PfFpkUFSfJia20FICUjOj81UKbehuUrk01bqvumoBEP8KqetlEW5EVfkU/yeJHlvine9sTz1q9fz9lnnkFKcnAoRiie97Prf8KPf3YTi36f4HkReV6Ebn5c8Ty9r5kbgugleF78QZCPFL1bGLS1tWG1WmltbSUtLT5HYQ8V7vjvBl75uopfnD6Ym88Ycrg3pxt+8o/VfLCplvvPG8GVk8oO9+bEPaY89An7W+y8fv0kxg/omTxVbVzHf+6/C2tePtc+8fdDsIU9w+Ww8+erLwHgxpf+g9Ec3YXJDUu+5e311SycPpSfTo3ds+Nww+FwsHv3bsrLy8OmW22vbcfh9lKenUyq2RByGRXN1ftx2myk5eSSlNbdu+1g4p133uHWW29l48aNIbugsixTt3snsiyTU1qGztB92x0OBzNnzWLXnipeeO0dTh59ZHXvbDYbWVlZvPfee0ydOrVX66hpdVDX7iAr2UhRnBnoh0J9u5PqVjvpFmPUKZA9YdOmTZx22mls374dq7VvPteRvosJ/tA/kDhOfvzxw2088ckOZk8s5bcXhE/yPFy4+80N/PPLKn5++mBuiUMeGm8478mVrNvbwl9/dCzTRxbE9NzFt95AfdUezl/4awaNn9hHWxgZnS3N/PUnVyIIIjcteQNRjD5R+d63NvHiqj38eEo5i2bG5lkdD4iG5+2q76DD6aEkI0lTM0VCIL/KLi1DH4JfHQxE4nn2jnZaa2swWixkFoaXuzocDmbNmsXOPVU895+3OXnUoLicLu4tDgbPa+hwcqDFjtViYIBveCGe0WxzsbfJRopJz8CclJ6fEAUSPK/vkJjkO4qwr9kn44jzDm9TZ9+NoR8pcHkCzLWj7PCqHi2ttTW4HOE9Ew4l1Ck+g8kcdYEPYEShciLYdODI7fDGIuPwd3f7dpIP4JxzzmHBggVBo/aBkLxef+JqGHNfs9nMm2++ybkXXcbqL1eGlHj2ZyxfvpzTTjut18QPwOVVuvSGfpI0rsp13d6DN11QXV3N4sWL+4z4JZDAkYb+othITPJFh9568kF8+PKpHM+SlhZTgQ9gRKFywb3pQOtB3654gUp9oi1+CYJwSPheJJ6nvq6qIAkHs9nM0qVLmXnR5Xz71So8h1k2frBxUHiex8fz4swnPxzU7XR7Dx5nT/C8vkMiXfcown6N/MXnVIgm40gYMveIAy12JBnMBpGcKM21k9KsJFnTsbW20LivioKKoX28lT0jVqmuipFFCvnbfAQX+WKRceh0qk9L3xf5QPHUCAdVMizqdRHNnpMsFq694RZkWcYjSRhjvACIZ5xzzjmcc845P2gdKvmLJOOIJ/jJ38Ej8tOmTTto60oggaMB++Kc52neywme1yPaHW7NvqY3Rb4s1ZfvMCbs9pbjAYwsUi76Nx9oQ5LkI2oKTEUstiwqdHo9Xrcbr8cN9F0xPxzPk7xKEIpO1zNns1gsXPfzW3B5JTxeGeMRVHU4GDxP5UuRbFniCYHNXFmWYwp0CYcEz+s79I9PVQI/GJIks68lvju8GQlPvqjhN2OOLTUrHjq7geiNITP4J/l2N3TS7jjyJj9lWUZteuqiILaHcpKvJ6jhH7oeuryCIGDwvTfPQewKHinof+TPV+ST5CMm9TqBBPob+otiIzHJ1zP2+vz4lBCK2GWZOSrfi4ciXwx+fCoqclMw6kXanR72+j7XRxpUb7NYenla+MZh4nvaJF8YpUZX6H2FIc8Rptg4GOh3zVxRDd6QtQL1wYAsK7xRlmS8Xgm3y4vL7sHR4cLW6qSj2ZHglb3AEVRTTyASGjqcuDwSOlGgwBraG+JwIzHJFz0Ci3yxIKd0AFUb1tJQtacPtip2+Lu86TE9LzPZSIHVTHWrgy3V7Uwoj51AxjMkGWR8k3xRFHH9pM/bp9sVDdQubzQEUK8TcHkT5K8rJFn2F/n6C/nTCQjgm8yUtY5vAgkkcGjg8kjUtDmA+C3yJZq50aO3PE+FmrDbtH8fXo9H4wmHEp3NTQAkW2Of5DPoRIbmpbJhfyubDrT1C8+yWKEWSmKZUjzcTV1VMSJGMckHoBdFwIv7CJPrHgy4+lkzVxQF9KKIR5Jwe2X0UXwEJEnG7fTidXvxemQkj4TXK+P1SMgxcP+kNCNCglfGhP7xqUrgB2OvT8KRn2ZGH6cXjZqMI0H+ekRvfVqyS8oAaNi75yBvUe/Q2dIC9E7KcST7tajdXQGBaLifRvoOkVw3EqQoJ/lAJX8kyF8XuH3dXVEQoprkjAcIgqCdWw6mZDeBBBKIDjWtDiQZTProbTwONTITPC9q/BA/PoDU7ByMFguS10NzdWgP3b5GZ2vvGrkqjmSeJ8uyf5IvJrmuMtV5qOxZukJr5EbB8QD0CcVGSHglSSvy9hdPPojOf9nj9mJrc9FSa6NhXwetdTY6mp3Y21047R48Lm/EAp8oCugMIkazHnOygaTUnkNpEuiOxCTfUYJ4l3CA35A5Qf56Rm87vKpctz5O5LraJF8vurzHFFr5aEvdERm+4e/uEpUcWy2oSV4vkiSFTL09VPDGIOVIkL/QcAVM8R0Mz5NDBYNOxO2VDqopcwIJJBAdVEljUYYlbn83AhUbB8vT6UiFyvMG9DKtXBAEskoGUL19Kw17K7XJvkMJrZHbC7kuBBb5FJ7ncniwt7uRJRnJKyNJMpJXwuuRcTs9uB1eXA4vbqcHQRDIH2QluygFIQ6bZYFyx1gm+TQP5sMl1/UVF6OdDE3IdUPD5VH2h17sP81cUHie3e3tVuTzeiQcnW4cnW687uDHRJ2IwaRDpxcQ9SI6nYBOL2rfS+00IAgIQnTXPQn0jESR7yiBasbc247goUBghzdB/iKjt0W+rOISEATsba10tjT3aoLuYMLW2jtPPuhO/o4kxJKsCyCIIoIoIksSkseDaDx8XS+1uxzVJF+C/IWElrjWTyQcKvoiYTeBBBKIDmoztyROQzfAL9d1e2U6nB5Se+E1d7Tgh8p1QZHsVm/fqvgwTz5YWxY9NLlujBxPkmT2bWki9ftOzuk0kP1dO89vXoG9PXYPZlOynqIhGRQPzaBoSAYZ+UlxUfRTp/hEQYjKlkXF4ZTrSpKE5Du/Ry3X9U2peRK8IAgqT+pPU3zg56VuryK3ddo9ODrduOzBn0eDWYfJrMdo0aMz9K+G9ZGCRJHvKEF/mORT5bpOj4Td7SXpSIphOoiQZZmqxt6RP4PJTEZ+Ac3VB2ioqjzsRb6Dkbz2fW07To8XUzTmEP0EsSTrgtL10un0eCSXr8t6+Ip8flPmno+HKtdNkL9g9LfQDRV9kbCbQAIJRAd/sm788jyLUYfFoMPu9tLc6U4U+SLgh8p1IdCi5fCoN9RGbrRqjY5mB1tWVbN55QE6mpwAHOO7VLW7lAKf3ihqU0CiKCDqlJvBrMdo0mEw6zCY9LidXqp3tODs9LDru3p2fVcPgMGkI7skhdzSNHJKU8gZkEZG3qEv/KmnyVgKfAA6gwEERbnhcbvRGw7dd0iV6gqCgBClYkRTbCSauUHQQjf6Ec+TZRkDkCQLyB0eGto6gmS3BpMOc4oBU5LhiEzD7m9IVFGOEvjJX/x2eJONOow6EZdXoqnTlSjyhUGr3U27Uymk9OZ4ZpeUKUW+vXsYMHrsQd662PBDinyFVjPpSQZabG6+3FxJgdmDLMvk5eVhtVr7ddco1kk+8BXV3IdPwqFClXJEG7wBCfLXFaqMw9jPTIa1Ip8n+uMpyz7ZlVeRXakSLFmWQV2N779q+pokyche//ckuzjlIL+TBBLof+gPPA8U1cb+FjtNNhelvZSiHunwSrJ2PH/oJB8cPh9mleP1pNaoq2zjm7d3U7mxETVE05Skp3xsDq9tr2GnzcFN5x/D6ccVYkqKvqjl9UrUV7azb1sz+7c1U7Oz1Vf8a6V6h9/nz2jRk1+eRt5AKwUDreSVp2G09O01iD9ZN7bzvCiKGExm3A4Hbrv9EBf5/PwuWo7tb+YmeF4g+kPohtcj4XFLeFxePC4Jt8MDkkwaAkhKPKCoEzAnGzCnGNAbjpxhiyMBiSrKUYL+0OEVBIHMZCM1bQ6aO90UH94hs7iFKuHITTVhMXb/QbXZbDQ0NOBwOBg0aBC6LiP12aUD+P7rVdQf5oRdWZKwtbYA0Rf5Wltb2blzJzt37qSuro5kZxYtpPLMq+8yRN+gLWcymcjLyyM/P5/CwkIGDx5McnL/SWbz9oL8+RN2+7bI19jYyPDhw/n6668pKysLeixQyhFd8EbCky8UXP0sWVdFT3JdWZaRPDJulxe300vNgVomTT2Oj97+nMKCol6/bsLeIYEE+odiAyAj2cD+FjvNCf/lsKhtc+DySuhFgQJr749ndqlS5GutrcHtcGAwmw/WJvYIl92Gy65ce0TieF63xFtPrMXZqXCXwsHpHHNiIQNGZdDe2cbLznq275T46PttuJvX4vV6ycnJIS8vj9zc3IhNXZ1OJH+glfyBVo47uwzJK9Fca6O+qp36ynbl373tuOweqjY3UbVZkRcjgDXHQnZxKtnFKWSXpJBdnEpyuvGgnWs07+VerM5otuB2OHA5bFjS0g7K9gQiHM+TPGroRvTFHH8zNzHhHwjNliWOeJ4sy7jsHuwdbjwuL1Iobi6AE5BEKMxJQm/URfxONDQ0cMwxx/Dtt99SXFzcdxufQDfEzycrgT6DJMns7wdFPghI2LUlyF84BPq0dHZ2smHDBt555x1efPFFHnnkER5++GGef/55lixZwjfffNPt+Vpn9zCHb9g72rXR/ySrNeQyLpeL77//nvfff58nn3ySxx57jLfeeotNmzZRX19PutxBkgSSlEVe0iByjRWYHXnQnE7dVhfrP93L+y9/zZP3/otn7v8vr/3lc5a9tJ7//ed7tn5RTeP+Dq0oFU/QZBwxsD9Rd2gSdh988EHOO++8bgU+8Et1BbG7lGPVqlXMmDGDjIwMzGYzo0aN4sk/P47X6w0if4IgaDer1cqUKVP45JNPtMfnzp0btIx6mz59urZMWVmZdr/FYqGsrIxLL700aD3xjP+t+IwxJRmkJ5sQBIG8vDwuuugidu3apS0T+B4Dbw899BAAe/bs8cm4dezfH5ysWF1djd7Xid+zZ0/Q8rm5ubS3twctP3bsWO69917t76lTp3LTTTd12+5/v/wPThwxALdX4v7776egoICG+gYcnW7aGuw07u/g84++wJqZwtI338KamsGlF17Ow4/9FlEnojfqMFr0mFMMWFKNWFKNJKUaSUpTbsnpJlIyzaRlW7DmJpGRn0xmYf8p3ieQQF+iPzRzwe/L15go8oWFyvOKMyxas0+SJFpaWtixYwdffvklb7/9Nq+++iq1tbVh15OUZiXJmg5Aw75Dy/n2bt4AQFpOHqak8NOIB75XJLWWNANn/GwguSfY+Xr7Mh597A88+eSTtFVuBmDNzlq+++471q9fz8cff8ySJUv405/+xEMPPcQLL7zA//73P+rq6pQp8DAQdSJZhSkMO6GAky4bwoW3jmf+Yydz6Z3Hc9JlQxh8fB6pWWaQobXOzs5v6/jqrV288+R6XrpjJc/9cgX//cMaPn15K+uX72P/tmbcLm+v9k9vJ/kAjBZlf7rs9ojvt7cIx/OkHjyXQ/G8Pz/+J7xeL17Jnyac4Hnwv88VnpeTau5znrdt6w46W5ysX7NV43ltrX4/c0mSGT16DLf98i5a6+247B7Ou3gGd//mdnQGEVOSgeR0E+l5SSxd9hojRpXQLsj87ve/pbCwkKampqDXXrduHSaTibfffpvs7Gyuuuoq7rnnnj7cmwmEQmKS7yhAfYcTl1dCJwrkpx26Ll5vkJmsjJ0nOryhIUkSG3ZVA+Bs3M8jj3wYcjmz2YzD4WDjxo2ccMIJQY+pCbuN+6qQJC+ieHjGq20+GYc5NQ2dXjnukiRRU1PDzp072bVrF1VVVXi9fgKlk0zkmgdhdmfj6dCR0+H1SfosSL5zTGqY1/O0Q+1+D7U0BN2vM4hKp7Y4hYz8ZKy5FjLyk0jNshw2TwmN/MXw8rpDYMZss9l47rnn+OCDD0I+HkgAAzt7b7zxBpdeeinXXHMNy5cvJz09nY8++oiFCxfy8Wf/45GnX0CSZc2b5oUXXmD69Ok0NDRw1113ce6557Jx40YGDhwIwPTp03nhhReCXttkMgX9fd999zF//nxcLhd79uzhn//8J9OmTeP+++/nrrvuOmj75GBDkmStw79p8xYy0q18//33LFiwgJkzZ7J+/XptOld9j4FITQ3+BhQVFbF48WLuuOMO7b6XXnqJoqIiqqqqur1+e3s7f/jDH/jNb34T87arFyuCV+bnP72FN/+7lPnzruOZPz8PgNvt5sZfXs8lF17OeefPwmDScd1PFzDhhOP5y9OPk5nZuwTGBBI42uHySNS0OYD4l+tmqQm7CZ4XFmqRLy9Zz8qVKzU+5HZ3D56QZZnLLrss7LqyS8uo2rCWhr2VFFQM7bNt7opda5Qm88Bjjw/5uCzLNDU18fXHWwBokw+w5PWPg5YxGo0MSjOyug46DBmceuqpCIJAXV0ddXV1NDQ04HQ6qayspLKyko8++oiMjAyGDBnCiBEjKC0t7XE7RZ1ITmkqOaWpjD5VmTSytblo3NdB/b52Gvd10LCvg+YaG06bp5vUV6cXKaiwUnpMFqUjMsksTI5q2s8/yRc7zzSYlcKQ1+PB63ajP4hha5F4ntcb3nM5Es9b9ukKHnn6BTxeGaM+wfMA3L7m9vqNm8nOTD9oPM/rkXA5PDzz1N8pyC9k3/69tDfY6bQ4cdmV34/2tnbuu+e33HXHIvR6EYfNjeRR7FAEUcCSYkBvFLGkGsgqDLZD0ZoOsszC227n7bff5mc/+xmvvPKK8r7cbq6++mp+9KMfce655wJwzTXXMH78eB555JEEzzuESBT5jgKoEo4Cq1lLOYpXxGOHt7W1FYfDQVZWFvooI+MPJtxuN7t27WLr1q1s27aN5a05QC6ivRkMkJeXx8CBA8nPzyc7O5vs7GycTid//OMf2bdvH+3t7UEnhPT8AvQGIx6Xk9baGjJ+gEzuh6CzpQWAZF+X2e128+yzz1JfXx+0nNWSQ7ZuEN6WJDobPHiADgCU4p+MjE2AAcWpitmrTjFjFkQlil3UiUh46Ohso7m1ibaOFpBEMswFSDYjboeX2t1t1O4OTukV9QLWnCQyC5LJKlImhjILkrHmWBD7+Hukkb9YJvk0uW7vusrR4N1338VkMmmFY0mSKC0t5a677uL666/XpMIbt27ltLKB7N69m+zsbObPn8+sWbN49tlntXVde+215Obmct555/HB/73B8AVzNfKXnp5Ofn4++fn5PP300xQVFbFs2TJ+8pOfAArRy8/Pj7itqamp2jKlpaWcfPLJFBQUsGjRIi6++GKGDlUudj777DNuvfVW1q1bR2ZmJldffTUPPPCA9l2fOnUqo0aNQqfT8dJLL2E0GnnggQeYPXs2N9xwA6+99hp5eXn8+c9/5uyzz456X65bt46bbrqJ1atXIwgCgwcP5plnnmHkmHHaMgX5eWRkZGjbPWfOHHbs2KFte+B7DIerr76aF154IajI98ILL3D11Vdz//33d1v+xhtv5I9//CM/+9nPyM3NDbteWZZxO714PZLi2+LyYm9zIcgCGV4BZ4eXJ/7wV6adcxLvfPAWF198MY//4WE6bG38+ak/kZKuTCmOHjuKwsJC3njjDebNmxf1/ksggUMBW5uLtgY7BpMOg0mH3qgY++vjLC2wutWOLIPZIJKdcviCl6JBQrERHna7ne+//54PV+4G9LTs38GyOv8EniiKZGZmkp2dTUpKCqtXr+b777/H5XJhDFPoyS4ZoBT5eqHecDsdfPLCsxQPH8GIU06P+nmyLLPr268BGNSlyLd7927WrVvH7t27aW1tJaP+ePRYsOnqMBgMlJWVMXDgQAYOHEhubi6tdjf/vm8ZjU6BsRMmY7X4Peg8Hg+NjY1UVlayfft2du/eTXNzM1999RVfffUVF154IaNHj475fSelGUk6JpOSY/wFCY/bS0utjaYDnTQe6KTpQCcNe9vpaHayb2sz+7Y2s+q/kJxuomR4BoXDU5GSw0/Z9caWRYXqy+dy2HE57Ae1yBeJ582+6ELl9XV6vvvuO8aPH98jz8vLy2PWrFl88H9vMPjaqzD6RIRHM88be+yxqFbUhQX5ZGX+MJ73ozlX8txzz/OTuT/H45ss/eeSxVx60RX88YmH0elFzMkGktKUz8m1c3/CX//+JNdcOZ+c7BwABEHxpswqSgm4hur+2VSK0sr9siCyePFixo0bx2uvvcbFF1/Mgw8+SEtLC4899pj2nBEjRiR43mFAosh3FGBvkyLhKInz7i4ohswQPx3etrY2nnzySVwul+IZmJlJTk6OdsvMzCQrKwuL5eDJY2RZ1kjLzp07+f7774O6t50or3Xy+GOYP+1y0kL4cZhMJoqKiti/fz/btm3juOOO0x4TRR2ZxSXU7d5JQ1Xl4SvyqalrPq+WrVu3Ul9fj16vZ+DAgQwaNIiSwgG8+6fttHV6AA+CAPkDrZSNzqZwcDoWq5HJj31Gp8fLR/MnUpHbswF/ZWUlL7zwAp3sYv7P5pOsz6C+qp2G/R201tporrXRWmfH65Foru6kubqTnd/6ny/qBaw+uaA1x6Lcci2kZVtIzTSj64WJrizL2AIkq51uL3ZJwinJdHqjK9p5BBG7JONwuzFH+RyAJDH6i9UVK1Ywfvx47W9RFLniiitYsmQJ119/vTbJ9/obS5kyZQoDBgzgjTfeoLGxkV/96lfd1jdr1izKBlbw/tLXuSGA/AVC/W65XD/8N+EXv/gF999/P0uXLmXhwoXs37+fGTNmMHfuXBYvXszWrVuZP38+ZrM5SJ760ksvsXDhQr7++mv+/e9/c/311/PGG29wwQUXcOedd/LYY49x5ZVXUlVVRVIEWVIg5syZw7hx43j66afR6XSsXbsWg8EQ5GcXeFx6ux9mzZrFX//6V/73v/9x4okn8r///Y/m5mZmzpwZVORTJT+XXXoZyz5cxr33/IY/Pfa4FoThsntorbcjeSXcTi/2djfNNZ1BryX7/Fu8gMEkMnLsMH69aBG33nkTphSRPzz6CP/85z+x2+3Y7XYEQUAURcaMGcMnn3zCnDlzMBgM3XxEE0jgcKFyYyOfLN7S/QEBpeBnFP3FP5MOnV5E1Anav6JO9DeedAKiAIJOxJykJyXDRHKGmZQMEykZJszJhl4XDlWeV5yRFFfFx1DITIovngdKEaCmpkZrlKq3rpNDBxsq39u+fTvbtm2jqqpKKZC5BgJZWPVuBg8ezKBBgygvLyc7O1v7fZRlmR07dmgS3mOOOSbka+QNrABgz7pvY/Yv3bh8GRuXf8i2VZ8zeOJkjObouG7dnl10NDdhMJkpPmaUdn9nZyf//Oc/NYWGXkpC77UgiHDZj8+lbFBpt9//9CQjRekW9rfY2XygjUmDsrTH9Ho9eXl55OXlMWHCBJxOJ7t27WLt2rVs27aNDz74gMGDBx8Ujq436Hweff6muSzLNNfY2Lu5iarNjRzY3kJni5OtX9SwZ3Mdo2ZaaamzkZKqFFDcepRqCn6elyxHz/MC4TGasNtsSJ2dyMmRue/B4nmXnz8LUNQaL7/8clQ8b+bMmZQPUnjedddcGfI1jzqe5/HzvMAib6T9IMsyXrcvCMOtBGGoHOyUSdN49tlnWLnyf0w8fhKrv/uK1rZWLrz4fP74xMNk5CeTlm0hqUP5PbtmwVWs+PIz/vzMH3jkd49hMOvQGZRzWSzDBW6vzLBhw3jwwQe5/vrr0el0/O53v+PVV19FkiTa2toQRRFRFDnuuOP4/PPPE0W+Q4hEke8oQH8xYwb/JF+8dHjXrVun/diqZKyxsZGtW7cGLZeUlERmZiZWqxWLxYLZbNZuJpMJg8GAwWDAaDRiMChE3uPxaDe3201LSwtVVVVUVlbS2Rl88ZyWlsawYcMYNmwYH/9nDzTbOfnYY0IW+FQMGzYsZJEPIKe0jLrdO6mv2sPgiZMPzs6KEV2TddevXw/A5MmTOe200wDY8Ok+nJ0eUrPMTJhZzoCRWVi6TCkMLUzl26oWNh1ojarIN2DAAEaOHMnGjRt5//33+fGPf0x6XhKDj8/TlpEkmY4mB801Ste2qbpD+fdAJx63RHONjeYaW7d1C4LSxU3LtpCWYyGnJJW8sjSyi1PQGcIX/2ySxKDPN/S47VFjT/Tr2nnyKJKjLKpUVlZSWFgYdN+cOXN49NFHqaqqIj3JgiRJ/HfpUn69aBEA27dvB2D48OEh1zlo8BB279oZFL4hSRJut5v29nZuv/12dDodY8eOpb6+Hrvdzttvv01KSvCxvvPOO7nzzjsjbn9mZia5ubmaD91TTz1FSUkJf/nLXxAEgWHDhnHgwAFuu+02Fi1ahOjzFRwzZgx33303AHfccQcPPfSQ1rkGWLRoEU8//TTr16/vJo8Ph6qqKm699VaGDRsGwODBgwFo7HB2W7a6upo//OEPFBUVMWTIEO0C6bbbbtO2S8V7773HSSedpP1tMBj40Y9+xPPPP8+JJ57Ic889x+wrZiP5VN1tjXYajR007lfmY1vr7Nx+y6+58trLmXvFfMoGDFTCMpxenDZfs0GGF//5d17+92I0OigoUxVGk4l6nUSq145J8nL11Vfx9tv/x5VXXsmPf/xjTjzxRK2gKMuyZqK+ceNGzddFp9NhNBq1309RjO8J9ASOXOj0AmnZZtxOJSzG4/JdnMngcXrx+AreBwN6kw5rtlk7fyjNJAvpeUmkZpgRIlx89Suep07yxUmR78CBAyxfvjzkY6mpqWRmZgbdrFZrEMeLReHh9Xqpra1l7969VFVVUVVV1c0DNTc3F1qzoVXmqgtncO6Y0Gb1giAwfPhwvvjiCzZv3hy2yDdo/ET0BiNN+/dSu/N78iuGRLWtsiyzbtl7gDLR9/1Xq6Ke5tu1RpniGzB6bNCU2fr16/F6vWRnZzN9+nRad+r48o3dFA3JYNCQ8rDrG1GYxv4WO5sOtAYV+brCZDIxfPhwBg8ezF//+lcaGhr45JNPOOecc6La7lghCAKZBYrKY8zpJXjcXqq/b2XvliZq9irnM69bwtbmoqHFwQk+7nFwYYOtdRGXOFg8b9fOXRQV5CPodfzrX//S+EfPPG8ou3buwCN1n2y02Wzcdddd6HQ6Jk+ejN1ux+PxHNE8r9Xe/ZxxYP8BHnlE4XllJQOxd7iQJVnheXfdTeCee+XF1zhhwmS8vmKh0WTiskuu4LWlrzDjgjN47TevcOWVPyI5NfT5QBRFfv/7h5g5cya33vYrBg0aFHK5p556ir///e9B9yk8T7H+am3vwN7m4rLLLtMm+a655hqOP/54bLbga6T09HQ2btxIXV1dyGviBA4+EkW+HwCXw4PHJaE3iOiMotKpjcMPqt+MOTHJFwtkWea7774D4LzzzmPQoEHU19dTX19PXV2dVvDr6OjAZrNhs9nYt2/fQXltnU5HcXExZWVlDB06lIKCAgRBwO2VONCqFBhLMyMfz2HDhvHxxx+za9cunE5nUEdaDd9o3Hv4wjfUIl9SegYdHR3s2LEDIEhasWWV4j845vQShp1QEHI9IwqtfFvVwuYDbZw3NrqpxDPOOINt27axd+9eNmzY0E3OIYqCcqGVbWHASD+hlCWZ9iYHrXV2WutttNTblf/X2WhvdOBxS3Q0O+lodnLg+xa2omy/qBPILk4hryyNnAFppBcb6QOv5D6H3W7H3CWdb+zYsQwfPpwlS5Zw3dyr+eKrr6lvaOCSSy4JWk4t7Hi9XpxOp5LEK0kgyxgMBlrb2nG0K5WnOXPmIIqiJpP/wx/+wKBBg3C73ciyzOTJk/nd734HKCTbYDBEndoVOMmwZcsWJk2aFPS7PWXKFDo6Oti3b5/m5xP4+dDpdGRlZTFqlH86IS9PKRDX1UUm2oG45ZZbuPbaa/nHP/7BtGnTuOSSSxg0aJCWrAtQXFysTHnabIwYMYJnnnmGxsZGbT9ed911XHrppdp+EASBoqIimpqatAtHu93B5ZfOYdoZp7Lwprv5z39e453/LqOzWSkmuuwevO7g8JnTpp7BxOMn8fs//pa///UFBFEpQKRkmHwBGSKzZ8/mrrvuwuv14nK5cDgcvPXWWzzx5z8DICFiNOowGAya385vf/tbcnJylJRd3/GXJAmr1YrT6USn0ykG3V5v0LSfyWTSCn6JKb8EDiWGTMhnyAS/VEqWlHRoj0vyFf2U4p/bpRT8vB4Zr0dSJmC9El6fz5HklZXPve9+R6eHjmaH73zhwN7uxuP00ri/k8b9nd22Q28QseYmkZ6XhDXHTJLVRLLVRJLVSLLVxL76TpD7R5FP43lx0sxds2YNoPze5ufnU19fT0NDA52dnbS3t9Pe3k5lZXiupNfrg5q56k0UxaBmrsfjoaOjo5uvniiKGtcbMmQIGRkZPP/AMsBFWXY4l2EFxxxzDF988QXbt2/H4/GELDiakpKomDCJrSs/Y9Pnn0Rd5Nu/dRON+/y+rZs//zj6Ip9Pqjvw2AnafbIss3btWgAmTJhARUUFS99WOHYgzwqFEYVWPtxcy+YDbRGXU6HX65kxYwaLFy9m9erVjBs3rlvhqi+gN+go8cl8HQ4HO3fuIiXDBF49tji4rokG4XjesKFD+e/Spdx8442s+vIr6urqwvI8FZIk+e5TeJ7D6aIT5fN/xRVXdON5BQUFNDc343K5NJ6n1+u1YlBeXj5ej+Tnk77/d732jleed9FFF1M+oByXzY3ZR7uKi3w8z25jxPBR/O0vi7G3egEvsgQ/XfBzLr94trKwAIIIRcXFmFP1pGQqv6UZeUlc97MFTJ48md/XP8R//vMfvvjiCzwRPLrPOussTjzxRH7961+zZMmSkMvMmTNH8zaUZRmn08lrr73GH31SXIfbg07wIggCN998M5deeil33303aWlpQRxPkiQsFgsOh0P7LbT7krdFUdQaJkajMdHUPYhIFPl+ADZ8uo8v3/Sn4AgC6IyKV4veIKJT/9UrqYGqZEPUKVp39V9FsqT4hwmigDFJT1KqEXOKgSQ1YdCqpAv2RgrYXxLXIL46vJWVlTQ1NWE0GhkxYgRGo5G0tLRuHQ+n00lTU5N2Ye1wOLSb3W7H6XTidruDbpIkodfrMRgM6PV69Ho9SUlJlJaWUlpaSlFRUUiyVt3iwCvJmPQiOSmRZSTZ2dlkZWXR2NjIjh07GDFihP8xX/hG/WEs8tkCJvk2bNiALMsUFRWRnZ3t27Z26qvaEfUCQyeE96MYUahMM26KkvwBWK1WTjrpJD755BOWLVvGsGHDwvrZBEIIKP6VEGweK8sytjYX7Y0O2hrsNNfaqK9sp3ZPG44ON3WV7dRVtgP7MVtFRs2y0lpvw5MMerOOnSeOBN+kxq76TmwuDwMyk0m1RP8z3bC3CsntJqOwCIM5upCdpBhOqNnZ2TQ3N3e7f86cOSxZsoT5V87hv//3f5w5bRpZWQppVzuXKtFqamoKusjZ8f02ho4YjdPjQScohOSee+7h5JNP1jxbdDqddjOZTNpkq8vlCpoKa2pqijjd2tjYSH19PeXl4ScGQsFgMAT9rRYWA/8GhdBGi3vvvZfZs2fzzjvv8O6773LPPffw97//nYmn+ycO/vvf/5KSkqL5L3VFZmYm5WXlgIggCyCLCAi4OsDRpuwXe7OHkSOOoWLQYOb9ZC6DK4YwfOgxbNyqTM6aknWkZBmxOpXzQ0ZBMjmlqTz62CNMmjSJu++5A51exGjWYUrW4/V6kWQJs9lMampq0HtWjzmAJTmZ7HSlEZGcnBy0H9U0OLVg19HRQUFBAXl5eUiShMvlwul04nA48Hq92u8poE34xTpBk0ACBwOCKGA06zEe5Awzr1tSGkj1dtoa7LTW+251Nlrr7XjcEo37/RO3XWEBfokZ8ZNGFn+zSkmpTvIlVacofNKcYsCcbMBg0mE06zCY9IrXoFmn/as7BL7NmmIjDnie0+lkwwZl8v30008POjfYbDaN2wXe2tracDqdOJ1Ko0S9aI0WJpOJkpISSkpKNL4XyD86nR4aOpR9U5oV3MyVZZn2Rgf1Ve3UVbXT3mgnzZhDm6uenTt3aj5eXTHi5NPYuvIztq76nKlXzdPCziJBneIbMHocleu/o2rTBtoa6kjLDu/VCkoDt2bn90Bw6EZ1dTW1tbXodDpGjRqFy+HhwPctymv0WOSLnecNHDhQU2288847zJs375AXEERRwJRkwGw2k5JhZGP6MBydbs03TVlIINl3zSfGkrYGNFcfwG23k5qVjcVqDbvcweB5F86axX+XLuXOu+7ilVdeYfr06SF53uTJk+ns7KStrU3jZzu2bWXIiNF02u3gm2K7d9FvOOnEU0hLtZKd5fOFkwQEQURET7IllYqSESD7Ar0QkG3QaFN+AyWPwrmba2xYcyza9fHh4Hmy7G/maA0er8wvf347M6dfyPsfvMf7737APffcwzNPPM+M6TNJ8r2vpa++R2pqKtlZOaSkpCIjIwsSMhKyIJORaaV0UCGyIAGyzw7PTYejhdb2FgAaGhoYM2YMFRUVXHrppQwdOpSKigrtty0cHnroISZNmsStt94a8vGUlBTy8vJwuVy4XC6Sk5OxBnzOdHojWelpGAwGcnKUY5ienh6Sr7pcLgoKCsjMzMTlcuF2u3G5XEiSpA3KCIIQxPESTd0fhgRD/gGQvMEdCzlAvtFXsKQqMdbJVhPJGSZSM8ykZKr/mkm2GtEbg78U/UnGkdXLDq8sy7S1tWlpW0lJSeTk5JCdnR1V8SYUvv1WMWIbOXJkxHWYTCYKCgooKAg9aXYwoSaulWQm9eiboI6lr1y5kq1bt4Ys8rVUH8DtcmIw9q3vTCgEynU/X7cOUMblVahTfOWjczCnhCekIwqVE87GA60x+c1MmjSJb7/9lpaWFlasWMHpp0dvKh0KgiAo30urifyB/pOgSspr97RRu6eNuj1ttLcqUxcel4RNckG7j1CYdZgseswyyKJIikGHRRC0grHFYonoBeIwGHB7PZhlCXMfnBzHjRvHP//5z273z549m7vvvpvvvvuOd97/gCf/8hftsbPOOovMzEweffRRXn75Za3AZ7FYeO+996jcvYtb7/0dRqOFzFTlOA8ZMoTJk0PLyHU6HXq9nqysLCX8we3WCIJaDJJluVtHGeDxxx9HFEXOP/98QJGWvP7660Gfm5UrV5Kamhr1ZGBvoHZE8/LymDNnDpdddhk//elP+cc//sH4U/1FvoqBQ8jMyEIURJAFfA1xZBkERHSSCb0ntERdkP3fA1mQuPyyK7j9roX87ncP4dF34BGU3xKbq52WtiaampUJwfr6eqqrqyktLWXGjBncfPPNuN1uOjo6qK2tBZQpQo/Ho5Fdg0G5iElLS9P2Yyz5Lxs3bmTq1KlAcFc3LS0Nt9utHVePx6ORzba2Nu11k5OTE93fBPo1dAaR9DxlUq8rJK9EW6ODllobLbXK1Hhnqwtbq5POViedrS68bgkRAVwS7Y2OXm+HqBeUIqBJH1QYtKQYsKQaFflwbhLWXAtGc+8uIfyTfL2TOcuyTHt7OyaT6Qd75m3YsAGXy0VWVhZlZWVBjyUlJZGUlBT2XCBJktaMcDqdmvWKevN6vVoTV23oms1msrKyIv5e7W22YZGgyGigblMziO8VWgABAABJREFUOxrttDc6aK2zUV/VgaMzeL+lpQ+lzVTPli1bwhb5SkePJSUjk47mJnZ9+w2DJ0S2abG1trD9y5UAnHTF1UgeD3s3b2Dz58s54cLwSb4Au75TUnXzBw3W7FgATRkzbNgwLBYLu76rR/LKpOVYQn7uAzGiSCny7ajvwOH2YjZEx2/OOusstm/fzv79+7WgiMMFnV5HdroO0hX5f12DDZ1HRgTkdjf2djd6k0hSmhFzUnTXLXJyMh1OB3qXM2o5bk8IxfPcTifnzZjObx95hE3bt/Paa6/x17/+VXs8kOedcMIJSoFPEhBkHR9+8CF7du/iN4t+T6rHhIjync3LKqai1Cfv7Vo3kwSQBQQ5wnldUIZrPC4vzTU20nMt6I26g8rzJEnG5fAok9g+qbG9w0Vboz2goKcU9cKhpKCM+XOvZ/7c6/nJjT/mldf+yZnTz8UpKOsrKssnPcOK3qBD1Hk0DztR1GtF4hRrksZrJUnSFA/+7VQsbi699FLuvPNOfve739HU1KQVa+vq6khKStL+bmtro6WlhaFDhzJz5kx+9atfaQqKhoYGrdlqt9uD7AREUcRkMmn7URZ1Uf8GqzxP5XfqdqtKEIfDof2mOp1OWltbNY6nNnXjUS0Zz0gU+X4AjptRxpjT8hV5hs8MU/vX0/3/2o+BFCDfkJQYalm9T1LkU/YON44ON/YO5Yff3u5G8sra/xv2hu7mgkIWzcl6zMkGTEl6xlZ5GI6B+uX7+d/qei0dzugrKBgtOowWpaOrNyhSLHUCMZIHTF8gVa/86DV1uHA7whNVh8PBnspKKisrqa2ro76hQZv06Iq0tDSys7IYXFHBmNGju3Vrwq1/8+bNAIweMSLithxK7K5tBaDYagq5TYqXnJOWOjtOm4fykjJWspLt27fj6OzUuiJGswVzSiqOjnbqdu0kt2zgIX0fAB3Nil+Jw+WmpqYGURQZWlGB26HIXrd/VQPAkOOzIu7/8nQDelGgxeamqraVwvToRyxOP/VUXn/jDVatWsWoESPISE//Qe8pHCwpAmUjrZSNVIp/druDqn37SE43IsoGjUS47B5cdg9WIAkRW3MnHZIDSfaCoEwdRAom0Ol0uAGvxx3TVFm0OOOMM7jjjjtobGwkI8NP3ktLS5k8aRI3LbwNr9fLrFmztNe3WCw8/fTTzJ49mwULFnDVVVeRm5vLV199xW233caPrv4xJ512JoiiVkyXvTIuh9vfSJFR/EhkGY/bi63Tzs6te3zdU+WiTxRE0qzpvt9RmZp9DWxavxVZ8LB3315effVVXnrpJe6//37Ky8uRJInrrruOP/3pT9xwww387Gc/Y9u2bdxzzz3cfPPNgL9jqxKrQIS6T5Mgh4Is4/F4sdscNDe38Jv77uXcc2ZSWlxGdXU169au59wZs8jw6snwKr+7XpuIyyCjJkkHr0+ZgKurqwUBREFGJ0Jyspl0axrJPi1IarKXLKvAjdfNY84VF5NqtSLqdJrBs06nCyl1kWWZhQsXctpppwVNzKmyYKPRSGZmZpCfSuB63F6vti8C/+26f2w2G2vWrOGBBx4Iue/0ej0pKSmkpKQETfUFXkyrk4IJJHCwIcsyHmd3n8xDjeQ0keS0FIoGBxf1ZUnC29nBtKfW0tLp5skzyyhPNeFySDjtXpx2Lw6bF4fdi9Om/O12SbhdkiI5dkm4nRLqV0/yyDg9HpydHtqbIvOepFQ91iwjOYVmckss5JVYMFl6LjQk+Yp7zZ0uOvbui5gu6vZ4OFBbS11TEw3NzdrN5WsWpaSkkOULQMvOyqJswABtoiQarP5GKUiNHT26V8dZLwikWCykxBDs4HW5uv2iy7JMc7WNXesa2fBNHTe0Kev74G8buz1f1AlkFCSRU5zMjm8bcLaAMT2LrVu3BvG8rhg66STWvLuUjcuXUTb62IjbuO6j95C8HvLKK8gsLGbo5JPZu3kDmz79iGPPnhXxYnvnN18CMGD0sRp383g82lTRKB+n3rVOaRqVDk/vcd9nGSEjyUCzzc2mqkZGF4Wf2A+E2WDglJNOYtnHH/PRsmVUlJdHHZrwQ+F2OoOsKQKhMwjY9OCQJQrMBmSHF9kLHqdEW70dXYGATt/zd8ng80ZzOexIXq8W6vFDEIrn2dpa+H/27jw+ivp+/PhrZu/cN+EISbgEFAFPjipSURC8KYhSBavSqlDEFkGlgBYQW+9asP6qaFsRq5ZiRTwB5esFIqAcAsoN4cqd7D3z+f2x2SVLDhIISYD308cYMvOZmc/MZHff+zmz2rThogsuYMyYX2MYBldffXW1cd6vfvUrbrvlVyTEJLPii095dNYf+OXNoxjU/8roe2DVsLusWCp6tUFF9jWw2nUMFcBtFKFroUmLNCAQDOB0OkOt3TAp95VwMP8AAV+AL77cyX/fe4tXXp3HzBkzaNe2Labfz2/uvDMU591zD/fefTebt2xh2rRp3DfutwQ9AUxTYQZNAt4gpfluTENhBEPf0cuLfBQdiB5bzucO4i2rvoJC0zV0PdSlttxdzrQ/TmHI4Ktp27YN+/bvY+13qxk8ZDDFVpPyivLL1NR4UlOSqhxLVTTa87rdFOcXHDmHphETG0NKcjJlxaHvhInx8STFx/ObMWMY/otfEBcfH4nVQsdSkUpSCH3HDY+Z97vf/S4S51VOEz6X0+HAZrViD1dU2O2RsZgDQROzIr1Z8Z5s+v2RdWGROO+RR6pss+s69pgY4mNiCAaD+Px+vH5/VKVJaWnpCTXaOVNJId8JCPp8/GX0sGMnbCiaE02PQ9PiQj/1eNDj0SJLAppmxQiYlBf5KS8KvZA6Evqg2LnqMPXtnKkIgjIqfgZBBUAFUMoHyodS/oqfHpRZBmYZyiwN/Zu6d18IK7PEQtvbyC/z8uyoX0TeSJSmYThjMWITCMYlYDpjq36YKYXu96L7vCiLFdPhRFltlJSUUFJSwrbt2/lwyXvYCg5gLzyEZtbc1MSflEawZQ66z8NbD42nudQdfJnci4y489BXfctfly8EPebI34MlGU1PQtOOvKyDvvVorQP4gGfH3onVXVrlmAumPdCIV1DVB28ugMy26MX5/P3u2wDQbZ2wx12NMktZOHsMULVVVmVJrYZx2JHGnx6cQjv3jjqfWwGWtp0wYhN48c+P4dzzU6M865iUNM67+XZKHVZs4YBcs6JpDtAcaJoNG4BPQ8eFhkJpAUxLgEP789D91QfEuqYADV/hQbSSfQ2e747JFnqc04X5Lz7LHSOHR237xeCfM2HKDIbdcD168W68odgDBQy6+Bzeef1VnpjzIjfeeGOkZnDKpIe5+zf3YZg6lrIgh0tDXXFKC30UHfBUm4egz+Sjjz+kQ5forhgd2nXk86XfoBFqxfanp2bxp6dmYbfbSU9P57zzzuONN96gb9++oRZppokF+Oe8l/njrFn8/e9/JykxkRE33sBdt4zg4PafAPB7PLhLiiO/AxjBIKUFhRzasQfQI+9FJYeKOLTzEGgaF/zsAm76xQgm3vdQRaB15C/LasRQVFDC+Pt+y6HDB0lJTmXwoGuYOP4hLFEpTZQKAEYo4qOiu4YKdeV4/KmZPP7UzKj7cOvNI/jTHx+lrDwUFBaXFHH4cGgMGSvgqWix5ysKbVflpWjuMnRvKODT/V50rwc06NCmFSOG/YJ/vb4ALehH94TGClPBIAGPm6K9u6POXXr4EOHSAq/Pz8HtoYL6orzQ3+KhndvxF0Z/OVv4v3dp1TKTs9q0irrHx6JrGsoSfbeEaGhBn4/nRv2iqbNRKwOdvTljQNf47KXprNKDmA4Xpq3iC9FR7z+aaYBpopkmmAaaaaAZZqirnLKiabaKzyEX6E40zVXx71h0SzKanoymx+AuDeIuDZK348iXYNM4jBnchxncixncA2bVmMNAh9xfo4BnHrgPl3mkMFGhYbhiMWLjMWISMFyxUF2rN6VA0ygrK6OsrIydu46MHWcpK8aevx+Lu7TWdwfDGYM7tyuYJl/97WlWzql/zHqiNEs6FttZ6PaO6JbkqG0eAjiCB1FGCcosQZnFmMYhlHEY92GDvd+D1dkXq+tiYkuzKXR8y7Pj7sJaXnuX1m3frqrz3/SB7T9GpS06kFfn7z1fL3yDrxe+AUAgPhlvm/ZoAT/vPvIAGuBIHIOmx/Ht4uf5ZtGxv53EtxhCYUxbnn/sCc4p3VinPEAoBtFzu+IBnn/kDzj3N84wNeE4L9+qH4nzKvHbU1GaTrmvFJtugqZjCTrR0MnPK4JgUZ3PZRoGB3dsO3bCOmgRF0O3s7vy0tw53HbziKhtN1w9hMnTpjPshusp3b+Pyq/uS8/vyVuv/ZNn577I9b+4htKKeG7KpCnc/ZuxFOkKVJCEQKg1WdBfiLd0b7V5CPjK+ejjD8ltnx21vn27XP7vow+horv57McfY/bjj2G328lIb8F5PS7g3wveok/fizlw4DCa0rHpsfzrpdd59LFH+PvLL5OUmMyIX/yS3/zqfooOh2JpI6gI+E08ZZXeA8J1zCo0Pt6RFb7Qd1xlcsGlvblp6FB+/9txoCkUFpRmBWXBsPgpKDrMbyfcy+HDh0lJTmbwwCuZeO/dlFb6SlOQtxejvOr7JIR6TUx/9FGmP/po1PpwnFeQF7p/pYcPUnIwFG/F6qG4TgFaOK7zedH8XrRAqFxACwZD/9Y0OmS3ZcTwYfxr/utgBNH8vtC1mgYEA/iLCvAD4ZFiSwvyURVxXsAwOVgx7FPRwVCh/aG9u/GXFkflNxLnZWdF0h9LOMZTugU0Hau04qs3TVXXp+k0UlJSQmJiIsXFxbWO1XQ8fMVFPD/mlw16zBNnR9OdoLlAc5Gf1IEN9s7EqSDnWg6hKR1NWUKBnLKgm9bQv01rxXodjYbp9qTMckwjH2UcRhmHMSt+1lb4F9QszM0ZA8CvDr2J1eXAiInDcFYN9HSfB0t5CRZPObrPg+73oh3156wsFgy7C9MViz85AxXulmoEsRcewlZwAN2omp/ynC6YrlgcB3ZjLzhwYjfihFjRrS3RrW3QrG3A1hrLMZ6PUkGUWYSmp6JpGsnORbRI2kKabz9JwXxAw1Qaawpbsr0slXZx+ZybtB+7HsRuMbDrBjbNxGdacAftuA0b7qANt2GnPGinNBD6WRZ04DGsnOiX7LLcrihnDM49P2KrGF/CFncjFlsOQc9XBL1fHPMYH6f1Z1N8Zy4qXMXFRd/U6/yG3Ym73dmhL0JGEIvHjcVbju4tx+Iuq/bv40SFg79WmS2qBH+m3UmBFo9DacSrILo6co8VCsPqRvN7IoXUuqZwWQI4LUH8poXSgAOnJUiS/eS0Pl388QomzniG9UvfjOpyFDB18n0x6Joiw1l14HgApTQKjVaUeWDUXTezL28vC994j7TUtGoSG6hIH47Kr+tKfVbDhV6R3yvG50OBbkPXYgjdO4WpeTE1f+h9JBwsKIiMZwdE/pYVhHpSVHQZIfwluW7vj26Pmy49cpn/ylv07X1J1DZFRb6VedRPA0ODYms8Jiap/sPHPE9zZGo6h+2paEC679Ax0w8ZOow7Rt3Gjddec9znzMhtf9zddb1eL9u3byc3N7fKYOMnM34QDedkPqdDC17nHwtfa9BjNrTDcS15Pf16rMpgpG0l2omMVWkaoS+ARhDNCKAHA6HfgwF0vw9LeXHoXVJzoOnJ6JY0NGsrdGsrdEtKlcMpowQzuAczuDdUAay8oLy80nooJRY7I/e9RaLNgulKxHQkoOxxoFkIjz2lUKEKBn85mr8czV+G5i9D95WDbsW0x6EcsShbLKY9FtMZj4YFDQ3N78dWWorFa6JHVYjHg1IY1gBBhwnBYiwle1DKA8qAcOW2CgJ+lOkB5aFqn8Ljo+kpWOxnodvPirpnSgUxAzv5zmHl/+IzOLvkW/oUfn2MgzlwJNyBpjspSdyM6f0e5/5dte/TBNxZHTHiErEf3ofj0D40SzqOhFtRKoCvaA7VtlY/yufJF/Nt0nmcU7KB/vmf1ev8hisWd06oa6ilrBiL143uDcV6WsB/UqqKaovzlNVGviURE40kzYPVrHidaVZ0LQkA0ywCs2laEX+8bBmPzv4Ty5csrtdnq7LZ0VUiGjoeTwGj7rqVfXl5vPn6ArSWHdCVSZo/v2EyqekoqxWlhWI63XShq2P31IrKbzgei8RiCkVFoV7kvaAi/gy3igv9gtvr5Zye5/HPf/yDPn37hJrvRQ4cKiQLvY9G/20rTeOQPRTzpvsOox2jEUNzddARajGd5s9HV7W/NzZInNc2B70OPfGqc6bGedKS7wSUvDafK79vmJqThqaA73r0YE2KhbUBg5Z6KV3YSmJREYlFRcS43ehKoVValKYRtFoJWG0ErQ4CVicBu4uA3YXf7iRgcxG0OoCKAkHTiq6saKYFXdlwusHl0fA5kjAtDjQ9FoseC7a2lTJm4vIcJrZ8D7Hle4kr20uMOw9boAyL4UMDXs7y47PYKWp9Fgm6L3JBDo+ftEOHaHHgAOkH8oh1uwnV+9btfhi6ld1ts9naqTNlCYkEk7Ox2Vtx7pqN6KadgC0Ovz0ev93Gj6otyu2jz4F9JDpaY3da0DDRKxYNE62O564PE50iLY18PZN8PZMiLQ2lRQcHbk2RZJaQoMpwKA8O5cGpPMSoEmJVCTFaMWnJ3/O9uoS17hvw+i+jt7GQGEcxVBo6oTTgYHtZKobSaR9fwNHigFRH9a2pwpTSCQRjCAZjCQRiQz+DoZ9Bw4Vp2qiuELDEDPKJtzBU/OJwYTcMhho2LDHpeIhhuTVUe3e5nkdMzLG73ijlZRNgdbXmBv+xa4k0mw1ry0ysLVtiy2zJ914vn2/dShAw4hIw4kJv9LqmcUWvXnTvVLfZ6OrKZxjs83hIyWyFs9J4FmVuN6VuD6YCj6bITY9DQxHwK8pLgxhBsBhONJdOakIMevl+CJRH7nCwYvwSQ7Njumqfle94XXXNjWzZU8DuQoOsNi0i642AAT4/FosF01XpmSkTFfRhBLy4jVSCyonLafL631/ihZf/xupvl9Nn4I2YmkZ2koNQpV0DvLKUIujxUV5mEjR1dOXCFrSgmQFM3YrSbaHg8HgPjwLNrAgSqSgVDP17xVdL6dv3Z/T62QUYuNHNINZgALvPi+WogE+z29EdDjSHA7fVwWGvwmm1kNEqNzpobEgVAagKGigjCEEDZVS0FgyPZxheIhmN/K/K71r431ooXM33hu5EYmIKVo46pmGEaoENg0OHDnHjlVcyetBV4PVHn6/Omues9uL0YNH0Ro7zNPS4WPS4OCyxsViSkrGmp2NNT8eSloY1PQ1rSjJ6bDyW+Fh+OnSY5z9YCX6I0/1oFeMWpaamkpSYiK7rFZO7hX6GxzH1+/34AwECfj9enw+PxxPqeqdbUHYLqiJYOLro5Zyzz+aaIUOq/eLvKQtwYHsp+7eVsH9bCYd2lwEJWCxdsTi6RqX9dXjEmdhbiZzIXbHUxlqxHN3j0gA8FUtlejVpw4dSYPUCZEBMx2OcGGyGB5vpxmGU4woWExMswhUswhUsxmGUox1VKWVqVryWBDzWBLyWBLzWBIrtLSmzH/l81M0gad5tZLi3kubdxrLEdnyc8XMAbizcxwU1j8xTwccOVvJj0qXElmZTnrSXwWW7aqyK2m6DDQ5INOCSGsK7VU44YIUcP5xTqWfdYQt85QKbggHlUF1n0vV22GGHtgE4tyJ8d9tsvBMbiqmu3JdPvA+2JbRjG5Du3UmPsroN4BpnOcy3SRCwpnH1Me8LaDYrtoyMSKz3ZdDgu8OHMeISMeKOjJsc43BwedeudGjRopaj1Z8fOOh0kpyaHhXn+YNBitxulBn63EqLi8VeacKbwqIAyrCgWxJIST/213RPeRnlZaXYHU4SKo2BeCJGjLiFA/mF+AxFgsNOIOAnNi4eV2z1YwBDaOipgiJfqLGIBq1ap/HuwoU899e/smnzZrq27ICp6aS1aMDxy4NBgocOYfp8QBGBmFR8ltDwHZpWUV+gm5gYmKaBWbliGGppo6BXLDUXKn2+4v/o07cvfX72s8g6q9WKy+XC5XSiVy7YVQqfO4i71I83EMqDDlis6ehWPTTxUaUJOitPzhnaP/K/SJikTFURpoXiq/DQYWbQJBgMDRVWU/lhqFtxKHY6umzyyC8VcW4kFDxyPhToFdXwypKGXnFMTdfQNQ2LVauYfNRCYXEBw0fczK9/O/6EYjWJ8+rvlGjJ99e//pU///nP7N+/n+7du/OXv/yFiy666Ng7cnJLaA/PncuhZ59r0GPWymYLBXDhn04HutOF7nSiuVyhL4oxLiyxcayLcfG1UqwLtmRNsA2Dk7zM7EAojd2OZrOCrqNZLEd+anrkDa/yiynyJ1Lx4vb4vJR7vJR73JR5fZR43Hy9Zw9B06RjQgIDW2QS8BqUlUNRuY0it41ij4VirxNvsOb+9BoKTTcpRsMHJGoB7IRaHppmzV92dc0MjUeFGfo3Zui7pNIwlY6BBbPacOTEaGYAW9CDNeDGGnRjC7qxBcpw+Ipx+Itx+Iqw+4qxBUOFkQAohYbC0O347QkVSzx+ewJlsa0oTuqAYYkexNThK8TvO8z7LbLZbTUZtvG/3PDTimrz5EgM0LpPIY7EIIay8u9DT1BgZpNi30hG8mKyvt9JbHk5mg6HLS4+iu2AywxwffkmzICOGdQwAxpmUMdiN7E4TKxOA6vTxOI0sbkMrC4Dq8vE6jx2rbYR0Ai6LQTcFoJeHcOrk+938Ym1PW7djtMC5Z260vLHvVzwTWiik+3ZV7E992qSCjdz3rqqry+FQtkAOyhLaNmQnMvkc8eS5itk3tcz0IKgBUILQSpaYtXO1DSKExMpSE2hICWFw6lplCSFAsHzv/mGDj/WvSvhMc/VsiXGlIdpm56Oo+LLUsBmoyw+HkNpFCoXmlJ0KD7SlcHUrJTHZoKmo+leUvW94cl4MQIahl/HH7RQVjFehssfwFbLYMANzW+14LFZsRkmMf7o8UpK4+Mx9Rh00wEK4gL7cTrd6JbQ68JQOodJILGkDGU0/Ad5wBaH15FUbaGZpkw0FSrg0sK1kZECO1VRiHekVQmYoFWM1Rcei67iPTL8UzdNLIaJFYVF09AsltB7tt0eev+u/LPSl+X8Mh97izwkOG3kpDWTceaUAjMIAQ8EPRD0g24Bi71isYV+6kfeYzfllRAwTDpkxBFjr1tdolIKTBMVDKKCwVBhoGFAMIgK/9swUcoEI1Trrkwz1O2r47G/oNfkTK3hPZ2czOdker2YpaWhQddVqHBaVRRWA5FvReEvPpFvRJUKzCPxVOWfFXGXZrGA1Yqm66E4LiYm6j2hNj/99BPz589nky+ZL4K5nN/KyV+Hn01aWlq9Z54OTwYUnsSovLyc8vLySHfYsrIyfvjhB0zTpEePHlx77bXHbOHj9wY5sL2EfVuLOLijJPQFtzyAp9SPETjy1UOh0K1gc+g4Y+1YrdbQ7YuMVV0x7rU/NJ5geAD8sNBY0hasdh1LZDxpcHvLKSsrIaj82OM0Luzdg9SWicQlO9i4bh1fff0dcYaDdrvzcfutBK0uTN2GqVsjP4NWFwFbXINWuGhmkJSCTbQ4uJq0/O+wGqHSsHVp7ZnS5y6CupXhWz7h9o1L6nQ8Q7fx5cWP4HckUhb/I72++hcZh6pvRe236HzSNQela1yyeTfx3ujxsTw2C8u6ZIOmcekPu4jzHfksV8CyLm3x2m303LGflsXRLfYVsLxzWzwOG+dvz6NFSajEdmPXLnx/7rmkHzzIz5cuA+Cbnr+jJLEdZ22eT+u8z495jQrFnvg0xlz+IHYjwNuLH8Jq1u/rqwIKk5MpTEmmICWFwuRkihMTMS0WNNPkoq9XkrOz4bryVhfnmbpOSUICpqaTr0Klz+2L90W1hDJ0K+7YloCGJVhKjKew1vMYukaZw46GIsHTsDNWm5pGqTP0vS3B66/SW6qy8ph4zIou5y7PYazB6BL7H5PaoIB2xXlYVMNOUKlZrFhbZGBJTo6M5axbtCrfZStPWhGePKzyuInhArPKk7eFf1YeezhccRKeUCf88+j3RMMw8ZYG8JT5I/nyaVComzitFtqnxUZmBW5oSimCAZOgzyBQsRjBhvtOkK8rApoi2dRxHOulqGlYbRWFmeECTWvjVdCeqXFes2/J98Ybb3D//ffzwgsvcPHFF/PMM88wcOBANm/eTEZG7dO4n2ypv/41qXfeeSTIg6qtH44WKTCrSFfdH3hFAIhWUTShaaEgsI4vhjVr1vD1okUAJLZqB7v8dL7wXJIvP84vQqYB+7+HXV/Cri+Jy/+Jo9tWXZrgo7CoCEoUtoCL1IQEND0AlnywFECcgjhwG4nkB3M4HMzhcCCH/GAOhcHWmNhQaCjTQjwQaoPkqFzfUnP2lI6pIFjfgjwNlB7EwI/FYZLdPov4ZBdr16zF9OtkJKSj/OB2BzCCOuqoWZ6UbsNvt+G3N+ybgt0eJC2tjNS0IlLSDvOTYTDx+7PxmwaXt95Jt8vtrNd/TrkGXi1Uce0DuudtYcC2b7Apk2K7i391uoyd2k7aftKGAn9XfmgToPTSXZExv3S/Qfor2/DoNr64N5cMR0lFV0QLWkW3RE1ZKrq+hBZd2dCxoWPHYliw+02cXi92bzl2nxu7twy7rwyrrxxr0IvFprAkBnEkhrq8HvTG8vGu9ngMOyl2N79o+z3xrMDoaMF3TgweWxxf7egDAUjotZUtw8/hkDOOw45YvJqOFx0vFvyanQB2DHRMLPiCNlgKhx3J3HfXBNpmHcCu+7ESxK78uDCJwcClFC4UqUGDsw+YxG91onYUENi7DyM/nxS3mxS3G3bvQQFru3Vjc8cOrL7gApTVRqdtDdOiQws3OddCrZ9MXae8YvIAmz8ANhcWot8fdAxivPm4Xeko04lPS8BulBJwW1FKC02+YAGrMglqOm67DQdB7BhHeqdW93ZzdE9YqJjZLKqs65g9lSIFXuHrqhC0WjEsTixGqPDa6S9ECwTw+W1Y7KFCZIvFpAVFkBguU9IwDR3TCLWXjXx3Dh87nLejKmWPujJ0uw3N6cTqcOK0hwpB0StqGS2hpcrban3rvSqeYeif2pEv8MfRfdRfUShrrxT0HamHq9QduVIeoz8XQt2KI+uUAsNPxewkke4okd8jBRLh7Ubo/T780wxC0Bv6eQzKFgOuJJQjDqsOAQO8fjc2TYUK5jCrBMtHWgLqFfnWwaKjWTXAjq5ZKrbpUosrmoTudKI76z6ZU2PZtWsXCxYswDAMHKmt4QB0bduCzMzM4zqepmmRWQxTUqp2uwXYsGEDb731FmvXrsVqtTJkyJBaX5d2p5WsLilkdTlyvPXr1/Of//yHjz3tOWwkMXFgB0b371Sv1tuGEfriqltCk8TVtm9+fj6vvvoqh0tK+HpbHqMuGUVCQgL//XAjfudhLhw4kIsvvpjCrR9SdngTuhb6xNEBTQv9xAwQDNjwea34PFY8bgtlpTplpRqlJVBWCtXNDaZpEBurERenERsHsXEa8QmKlm10rPYOmGRhqqswlI9tpQFmrGhBMGjh0pb53HiViwPaNXiUiRsDj1J4UfiVItSJGIJohIvgHD9uJ3Z1D1y+Nix7qAdOZ6hyM3IthFre6YD2/n7UDjdfDz+HuD5pWCu2WdApWZUP3xQQ28qF996rACtOTceGBRs6bb/ay5Zv9rLvsq60u/ZcwmcBjZJ8N57XvkS36GT96WYstlDL0bLNG8kMbqHrBZmom4fj9looeTs0pq7ngZZsirkKr1J4MPEq8KDwouFVGn40jIoloCxYlgbxY+N3991Ll9wdOC1BbCgcmsIFuIBYLTRxWbLSaFccR8yuWMw9+QT27cNx6DAtgkE4eBAOHsTQNL5u145tGRl83bsXqkUGnQ40zBA9Rno6hsUSqtCzWFCaRpnLhdJ1LIYZaVRhsUV/FbcCFuXG0GIxrHGYDu+RQrHQoMNUHmHEEloVGs8y1oZFq/Sd9EgyolYqLRJSHBmapOo1+CtCEZui1q6SpqZhWBPQFFiUH5sehKMmSdCViaHpGA4H1qNjCq0ic9qRODUUf1afr8o7WhLisaanhypMCE3oUW1KTcNisdQ4MU1DMYImPk8QX3mAgO9IYaZu0XHF20IXVuLFabOctAI+CF2vzR4qUAt37AlP/BmuPAn9O7xDeL/IASIdNsK9NcLDu2qawl3kIeA1cCRpJDk1lGmiTANTVUw0GjwygUmoDlfD59HwuiuGwdF1rDYrVrsVm92K1X5y78eZqNkX8j311FPcdddd3H777QC88MILLF68mJdffpnJkyc3ad40XY8aJ645fAXZvHkz77zzDgB9+vRhy44YwE+aq4ii4nV4DT9ew0ewYpyxo987dS1UvOMo3EPMzm9w7l2LPW8TeqD2PhQOIBJaVtdlAsCVQkxMKjFOK1mOYnBsA/shTPU1JZu/wuYuwq9i8KsYAqYTrBqurgOwnn8Tlow2uAPbKfeVUhb04vZ5KQ/6cAf8+AIGfr+JP2ASCCoCAYWua9hsYLNp2G06dptOh+RMOrQ4H5s9Ht2io+saxcXFvPLKKxwuLMQIbuei3Iso2vIDCa0cpA328+/9h/gy2B03sQSVhl0Z2M0gDjOII2gSGwgS4zdx+k1cfoXLBzEejRiPhsurE+OxYA1okc8vCP2dmLrC6zTxOg18ThOv06QsxmRfhsnBRAsBzYWfRHzu9hhfl6OZCiPdyeKze7NY6xO5pZoy6Vy+nck7/s7A/JUAfJTSm/vOmky+PQmAXt08XLHOQ9K67vw781IK4yo+4JxwV/wTJJUW8efCsbRptY/BvEMOO471ZxZirXjwVXqFakAcuhGLw2fi9Bk4fSZlB1x8tbUDAcNKfKyf7h1LcKs44v0FWJRBjLeUguIc3IEU7Fo5VxX9E2txqFYyiIV8eyKHbCkctidxyJbMAUcaO52t2OVswU5XS/QMC+ZBg582t2HrnhyCnRMx05zVvzAt4Mzy0KnNJq4K/MCgMoN2vgTsjhQ0ix10K1jsdLbY2LFnOzv27ifYw4pjxCByO3ap1IrJDlZHRWsmx5GWTVZHaIlJA0d8lcL8cK2SMzcXu93O4cOHUcFgaLr4lFQ47EGz6gTatySoTAxlghEksbwALZBPuZlKqZGOOz6BQBIVBWFHlriyUmweHz6sGE4Ne3z1M4HVrKaoSiOo2fEQQ7Di4yN8ZdZSL7ongCfRRVlMpeAuoOEoDc0UGHAEKUtxgnJGncFWGiSJMmI1DxZNhQqHbdXX9IY7yodiv/AYKaFCzqOKjjBs4LfrGDYdjWBo0So622saphb6gqJpOhqhbgZHCsoqX124MOrYlS1KmShloMxARW1wqEuvoUwM0wj9VCaGUhiqYo44FSqvLPOGvm6VBcvZVlpCuHGQqpQPFXXXo3/TlYnL8OE0/TiN0KI3wHgvCgjq1siiKROLMrCYFQsKLeCGis+Jljgp0uI46Ilhr2lHhVIQ/WIM5z28JdyFJVDpL9lED//UQt1DdKj4txb6qWmku9KlEFCcMfLy8njttdcIBAK0b9+efEsWHDhAizgf5eU/YhhefEaAgBkg3MUq8sXLMNHR0bWKJfyfrqPrVnTdiqbp6LoNq92GbrGia1Y0zUrnzu244YYb+M9//sM333yDxWJh0KBBdX7tffPNN7z77rsAZKTEsSsfPBZLpJBOKROPZxfeQBHlfjflhhd3wIM76Mdn+PEZQfymgd8M/dQ1DZtuwaZbcOhW7BYruXGZtE09H6s1VGmWmprK6NGjefXVVykoKOCVV15hwIAB7N+/H6sVtIw8Jn35FJ/6OnCYC7ESxEoQC0bFzyBWDCz4sdrdWOwGeqKB3lJVDN1y5H0KFJoKvZeF5sAKVdSZFe9woXopnUDQTiBow4+dADF4fYmUfQ0qqDCTbHx4djc+NM+t19+E3k7xm83FpJY5Wf/Tzfzf2TXP9tvxrI1cv2M+BVsNZl18W2hgeyC+tIhfbvwbccDrXa9ls9Gtyr4p7Q9wxzd/IW9nIVcVdscTE0f4Cnv++CV9gO2tchhg9kb5Qtdt5F6CgRVTs0AQuu3xcT3l7E+y8Efn0JorEI/+s9LA2qoI6+5ytmzL4Ye89gQ7JWK2cEYnrvSRl5BQxFndNtP9Qhs/S+1Or5bnkxjXEa3SMDgdTZP333+flStXsrJdOxLGjOFnlbpgHq9wnOfIzcXhcFBQUIDh86HrOgmpaRw85EbXIJidgaGMipggFBuYCvQiE93QKYpLxhsbqBLnqUrxQFxxCTa/n4MxCXhc1fdPrzz2m4UgsZQTSzmWSp3yw5VqpmbFo5xw2Aemwpscg9dxJOYLFyOqit80jwWb24ICypMNyvSEyLbwmVWpBiYcSInHYjUrRQBHfkbHCari879i0cCCwqqFZrW2ajpWPRS7acEStGDoOBoVre0qKjz1ip/hWA/CFY2Vl4p9NahLpWI4tgMTI2hgBAyCQQO/L0DQMFCaidJBxSiwamhWDVOHEqDUHYrzvKabnaUlkecYaQweufrou12lOjdcKBcVIVbUO4evp8q68Noj6aPLd1Wknts0Q0/YrMhb6Go1TBV6Mn4zVG1w0GdwKJILCypctFQxtELlJxy9mGj40PCgBxVaMPT+qVekDZVHhGI8i66R7ErBqjf7YqtmpVl31/X7/cTExPDWW29x/fXXR9aPGjWKoqIiFlW0VqvNyWyG+b9ly9mydXWDHvNEBIN+Sj15eGIseJyxlFpjOLAlDuUDo0s8wYSaP/Q1FDnevVxauIpLC9fQ0h/d1L/M4mJNfGdWJ3RlS0wOpqajV8w2pKOw4SeBMhINN05POTFePzGWFJSrJR5rAh5rTJWx5cLcJQfxFB/CZXroFGeiCg5xtm89HfQjs4N+HXc2r6Zdw05n6xO6RwmqmHRVQLoySTacOAwXpgpQlr8HwwigaQp7kg8HBq29hXT07KCdby92FSoU9WtW/LoNPza8ugOPbsejOfFYnLh1OyXWBA7akjloTeGgLYUDthRKrHGV3oLrwVRYfyxF9wQxY60Euiah65ARKOT80o30LNlIt9ItxBuhL9YBzcI/skbyYfpALJrlyBu5UlzwtYWUQp38eB/fnxsMjbsDnPX1YlIO7GRH607ktcjBZ3eRaNVor3tIUEE0jEpNpkx0zQAttF7DAAIVX87DTaog1JUx/HEdWmeUBvCvOYBuGBxMbc3SvjcSsIVadtnMIKmBIjL8BXT9KZH4gnQcyd/TKflNWvkOku4/HGrVdqzbhcZhSyrbAxlsN1uwQ2VyKK4l/laZGFaNAApDC037kujPp2/pGi4r+ZbMwMmd4CCoWSm3JFBmiafckkiZNQFPfDapPW+mVZs2aFYLBiamrmPoFgKGBfwqNBGKzcBh+nGYfpymHw2FgYXDZGENWjA0KIrVMKv583L63MS6K2bZs+roLr1SlFC1sCX635WLlhRBrPix48eBUUOL2Th3Cdagn7LYBHz2UJCpK0hyKywm+KxQGKtR3UtBKw+gGaCcOg49QKzhJcb04DT9obaayowKUOsrqFkoscRSYokjoNUeJESHnJWF3uusFXdAV6GWD6EgKPS3ZaARjBRFHSl8rSvNZ6CZCuWwoI5Ro2lRBg4zEPn7cCg/drNqYa5Cw9T0SoWjWtS/VaV/G+iYmo6hhUYfNTQLPt2GT3dg1hL0Ws0gicEyEoNlUTNlAgQ0Kx7dgVt34tGdBGv4HDheGoqOySky8cYZ7GQ+p/e/+Z6v1x1j8oNGZJgBisr34nVpuF0uSu3x7N0cT7BMg86xBNOdGNrxDU6OMiLjDofexaJ/WvGTYhaTHCwl1ltMXFmABF8isZbUo74vV6qEqHgb9QZKcXtDsz+67ClsKm3N+lKd7CQv6a1LKbTZKLDGUkAKfs1RNW/1kKwKaKEKyVBBUg0XLjMGMxig5PBuzIAPdChNtbEroRW79bbHPuDJpBS2zSXopQFMl4VAjxSwhd4jdWVgx8CGwqZMLBXVJRYVbnlH1Nh7mXk2eq6LJWAx+eLCEoyKFk3hxlCRKM006f3hfOx+H9s7nIvD5yE5Pw+XOzTQnc/hYsnAWwno9ioVlAD9P32TtIL9bDzrQna27RxZf9E3H5FauJ9vu/fjp3Y1F1L22WSh/QGdb9oHWXOWHysm9orrs6tQEYENsKGhKe1I35KKVmfF+QEO7HIT9IVKB50JVuKzHZh2CI3QohHQNDxYMY76vLGpAKkcJkWVk6oMEk078WYsutJxlxzCUxyKB12JaThikur6FKsV63DQt9NZtG7TBt2iYxCMxHlB04LhAXQNFVt9TGI1IKUsdP+LYxTBWj46HV43MZ4ygjY75fUcjzkU2fmwYOAnVPgcxIYt6CfGXYqpWyhOSK2xJYumIKk89HxKneCpoe+m5jEgaKIcFqihtV1jqCnGC/8e6h9kYlUKXWlYKpoWGpoKLWgENT2qCBKoc6yn+czQfXBawHYKt1zzm2g+A6w6ynHyr6N9jAuX8/g+G87UOK9ZF/Lt27eP1q1b88UXX9C7d+/I+gceeIBPP/2Ur7+uGnj5fD58viOzEZWUlJCVlXVSHt7fZg7n0n9+36DHFOJk8DhSWHnhQxjW6ILegOcLDO9XjZYP3ZqNLe5atGN8Cblg9eMklDa/GeIaSnVjtdSHQsMdk4lpqf0+KuVHGUUcu9N7w9EsyWjaUd00zAAx7gNHxrwTogFZO3XAZj++LpVnavB3KmvMOO/mZ59j6ty5DXpMIU4Ghcaq8ydRFp91zLQB91IM39qj1mpolhZYnRdjsbevcd+g7zuC7o9r3O5IuBPNcuzX4XnfPklSSfOcvLAhnGicB+B1pBCw1zzZRZhSQZTRQLPWHkXT49D0Y48RrBt+Yt37T0oehDBzs4mNPb4JBc/UOO+0a/f42GOP8cgjjzTKuQxpNipOES5fAV02v8bmjjdhVvq71a1dCNgDKLMMpbxRS0MXDFmt7bA7L0UzgoTa01UvtWAD8adxAV9D0FC4vIfwONOinmfVdFY0SzLKLEWpY4+rdsL50kJjN1KpME83g7i8+VLAJ4RoEI0Z553KDS3EmUVD0enHN1nf9VdVJnCrktbaFW9gJxoOLNaW6JZWWCyZRyrogjVMvQvoejamno5pFlfZZrXmYlW2WvcHSCzZTmLJ9mNf1BnO4S/CsNhrjfMANHTQ7ChV36FZjkHT0TRHVExXbTJl4vKenEJGIYCK4XREfTTrlnzH0123MWt4g4EAhftP31ooIcTJEQiaFJQFyM7Oxnmczc+FECFWq/24JjqBM7eG91TWqHGe30/hno0NekwhxOkvYCgKvDrZ2W1xOiTOE+JEWG1OifPqqVk3RbPb7Zx//vl88sknkUI+0zT55JNPGDt2bLX7OBwOHI30Zmq12UjPOqtRziWEOH14vV6Kt2/HZnccdzdDIYQ4EzVqnGe3k96uR6OcSwhx+jgS57mwOSTOE0I0rmbfEeH+++/n//2//8err77Kpk2buPvuuykvL4/MtiuEEKLx5Ofnk5GRwY4dO5o6K+I04/f7ycnJ4ZtvvmnqrAghhBBnJInzxMkicV7jafaFfDfddBNPPPEEU6dOpUePHqxdu5b333+fFi1aNHXWhBDijDNz5kyuu+46cnJy6rXfF198weDBg0lOTsbpdNKtWzeeeuopDMOISqdpWmRJTEykb9++LF26NLJ99OjRUWnCy6BBgyJpcnJyIutdLhc5OTkMHz486jjN2fLly6OurUWLFgwdOpRt244MD1H5Gisvs2fPjqRZuHAhvXr1IjExkfj4eM4++2zuu+++qHN5PB6mTZtGp06dcDgcpKWlMWzYMDZs2BCVbvr06fTo0aPGPF922WWRPDidTrp27cqcOXMAePLJJ0lOTsbr9VbZz+12k5CQwHPPPYfdbuf3v/89kyZNOo67JoQQQogTJXHeySdxnsR5J1uzL+QDGDt2LDt37sTn8/H1119z8cUXN3WWhBDijON2u3nppZe444476rXfwoUL6devH23atGHZsmX88MMPjB8/nhkzZjBixAiOHhp23rx55OXl8fnnn5OWlsbVV18dFfgMGjSIvLy8qOX111+POsajjz5KXl4emzdv5h//+AdJSUkMGDCAmTNnHv8NaGSbN29m3759vPnmm2zYsIFrrrkmKlgOX2PlZdy4cQB88skn3HTTTQwdOpSVK1eyevVqZs6cSSBwZGBun8/HgAEDePnll5kxYwZbtmzhvffeIxgMcvHFF/PVV/Wbefuuu+4iLy+PjRs3Mnz4cO69915ef/11br31VsrLy/nPf/5TZZ+33noLv9/PL3/5SwBGjhzJ//3f/1UJPoUQQghxckmc17gkzhMnjTrNFRcXK0AVFxc3dVaEEEIppZTH41EbN25UHo+nqbNSL2+++aZKT0+P/G4YhmrdurWaM2dOVLpvv/1WaZqmduzYocrKylRqaqq68cYbqxzvnXfeUYBasGBBZB2gFi5cGPl97969ClAvvPCCUkqpUaNGqeuuu67WfGZnZ6unn366yvqpU6cqXdfVDz/8EFm3fPlydeGFFyq73a4yMzPVpEmTVCAQiGzv16+fGjt2rBo/frxKSkpSGRkZ6sUXX1RlZWVq9OjRKi4uTrVv31699957tebpaGvXrlWXXXaZiouLU/Hx8eq8885Tq1atUkoptWzZMgWowsLCSPrXXntNAZG813SNYePHj1eXXXZZrXmYPXu20jRNrV27Nmq9YRjqggsuUF27dlWmaSqllJo2bZrq3r17jcfq16+fGj9+fNS6jh07qhEjRiillLrxxhvV5ZdfXu1+N910U9S6/v37qylTptSa94ZS22tR4odTgzwnIURzI3FeiMR5EudJnNc0TomWfEIIcTpTSuH2B5tkUfWYYH3FihWcf/75kd91Xefmm29m/vz5Uelee+01+vbtS3Z2Nh9++CH5+fn8/ve/r3K8a665hk6dOlWpna3M5XIBoXE8TtT48eNRSkVmZt+7dy+DBw/mwgsvZN26dcydO5eXXnqJGTNmRO336quvkpaWxsqVKxk3bhx33303w4YNo0+fPnz77bdceeWV3Hrrrbjd7jrnZeTIkbRp04ZVq1axevVqJk+ejM1mqzF9fe9DZmYmGzZsYP369TWmmT9/PldccQXdu3ePWq/rOhMmTGDjxo2sW7euTuerKc/h/N5xxx0sXbqUnTt3RrZv27aNzz77rEqLgYsuuogVK1Yc93mFEEKI5kTiPInzJM47QuK8k69Zz64rhBBnAk/AoOvUD5rk3BsfHUiMvW4fBTt37qRVq1ZR60aOHMmTTz7Jrl27aNu2LaZpsmDBAqZMmQLAli1bAOjSpUu1x+zcuXMkzdHcbjdTpkzBYrHQr1+/yPp3332XuLi4qLQPPfQQDz30UK35T0lJiRpMes6cOWRlZfH888+jaRqdO3dm3759TJo0ialTp6LroXqw7t27R67nwQcfZPbs2aSlpXHXXXcBMHXqVObOnct3331Hr169as1D2K5du5g4cSKdO3cGoGPHjjWmzcvL44knnqB169acddaRGd0nTZoUyVfYkiVLuOSSSxg3bhwrVqygW7duZGdn06tXL6688kpGjhwZmZl0y5Yt9O/fv9pzhp/Xli1bah2jpTqGYfD666/z3XffMWbMGAAGDhxIq1atmDdvHtOnTwfglVdeISsri8svvzxq/1atWkUFiUIIIcSpTOI8ifMkzjtC4ryTT1ryCSGEqBOPx4PT6Yxa16NHD7p06RKp5f300085ePAgw4YNi0pXW02y3W6P+v3mm28mLi6O+Ph43n77bV566SXOPffcyPb+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MYUQQgghxLE1ZZw3evRoNE2rsnTu3LnBrk8IIU42a1NnQAgh6uPxxx/n888/Z9iwYZx77rns37+f559/nvPOO4+vvvqKc845B4A9e/Zw6aWXkpiYyKxZsygrK+OJJ57g+++/Z+XKldjt9irHLisr44EHHiA2Nrbacx/PMYUQQgghRN00ZZwH4HA4+Pvf/x61TiYMEEKcSqSQTwhxSrn//vuZP39+VPB200030a1bN2bPns2//vUvAGbNmkV5eTmrV6+mbdu2AFx00UVcccUVvPLKK4wZM6bKsWfMmEF8fDz9+/fnv//9b5Xtx3NMIYQQQghRN00Z5wFYrVZ++ctfNvyFCSFEI5HuukKIU0qfPn2q1M527NiRs88+m02bNkXWvf3221x99dWRwA9gwIABdOrUiX//+99Vjrt161aefvppnnrqKazW6us/6ntMIYQQQghRd00Z54UZhkFJSckJXokQQjQNKeQTQpzylFIcOHCAtLQ0APbu3cvBgwe54IILqqS96KKLWLNmTZX19913H/3792fw4MHVnuN4jimEEEIIIU5MY8R5YW63m4SEBBITE0lJSeHee++lrKysYS5ECCEagRTyCSFOea+99hp79+7lpptuAiAvLw+Ali1bVknbsmVLCgoK8Pl8kXWLFy/mww8/5KmnnqrxHPU95ukqPz+fjIwMduzY0dRZEaeZXr168fbbbzd1NoQQQjQzjRHnhfd94IEHmDdvHq+//jrXXnstc+bMYdCgQQSDwQa8ouZL4jxxskic13ikkE8IcUr74YcfuPfee+nduzejRo0CwOPxAKHBk4/mdDqj0vj9fiZMmMBvfvMbunbtWuN56nPM09nMmTO57rrryMnJqdd+X3zxBYMHDyY5ORmn00m3bt146qmnMAwjKl3l2ewSExPp27cvS5cujWyvaea7QYMGRdLk5ORE1rtcLnJychg+fHjUcZqz5cuXR11bixYtGDp0KNu2bYukqXyNlZfZs2dH0ixcuJBevXqRmJhIfHw8Z599Nvfdd1/UuTweD9OmTaNTp044HA7S0tIYNmwYGzZsiEo3ffp0evToEbWuuvNXXqZPn86OHTvQNI21a9dWuc7LLrssKj9Tpkxh8uTJmKZ53PdOCCHE6aWx4jyAxx57jNmzZzN8+HBGjBjBK6+8wsyZM/n888956623GvKymi2J804+ifMk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vLw8zjjjjBThc9ppp1FRUZEyvfzyyynbuOeee6ioqGDdunU8//zzZGVlMXnyZObMmbP7J2A/s27dOnbs2MGrr77KqlWrmDp1aopYThxj6+n6668H4IMPPuCCCy7gvPPO44svvmDp0qXMmTOHaDSaXD8cDjN58mSefvpp7rvvPtavX88777xDLBbj6KOPToqzjmi938cee4zMzMyUeb/85S+Tbf/73/+26evhhx8OgMPh4Mc//jF//OMf9+bpUygUCoVC0QOUztu/KJ2n2GdIhUKhUOxXgsGgXL16tQwGgwe6Kz3i1Vdflfn5+cm/DcOQ/fr1k48//nhKu6+++koKIeSWLVukz+eTubm58txzz22zvTfffFMC8pVXXknOA+S8efOSf5eXl0tAPvnkk1JKKWfNmiXPOuusTvs5YMAA+eijj7aZf8cdd0hN0+TatWuT8z788EN55JFHSofDIfv06SNvueUWGY1Gk8tPOOEEed1118nZs2fLrKwsWVBQIP/yl79In88nL730Upmeni4HDx4s33nnnU77tCvLly+XkyZNkunp6TIjI0MedthhcsmSJVJKKRcsWCABWV9fn2z/0ksvSSDZ946OMcHs2bPlpEmTOu3Dgw8+KIUQcvny5SnzDcOQRxxxhBw5cqQ0TVNKKeWdd94px44d2+G2nnnmGen1etvM37x5swTksmXLOu3LwoULpcPhkIFAoNN2e5uD9beoUCgUit7LwfpsUTpP6byOUDrv4EJ58ikUCoWiWyxatCg5KgegaRozZsxg7ty5Ke1eeuklJk6cyIABA3jvvfeora1NGe1LMHXqVIYNG9ZmdLY1brcbgEgkssf9nz17NlJK3njjDQDKy8uZMmUKRx55JF9//TVPPPEETz31FPfdd1/Kes899xx5eXl88cUXXH/99VxzzTVMmzaNCRMm8NVXX3HKKadw8cUXEwgEut2XmTNnUlxczJIlS1i6dCm33nordru9w/Y9PQ99+vRh1apVrFy5ssM2c+fO5Yc//CFjx45Nma9pGjfeeCOrV6/m66+/7tb+9pQjjjiCWCzG559/vl/2p1AoFAqFIhWl85TO21conbd/UUY+hUKhONBICRH/gZl2CaHojK1bt1JUVJQyb+bMmSxevJht27YBYJomr7zyCjNnzgRg/fr1AIwYMaLdbQ4fPjzZZlcCgQC33347uq5z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R5Yur/LWUdeuXZkyZQqzZ89m//79LF26lFdeeYWuXbvqWmBKl1deXp72nRB8E++lpKRoP/aPHDmSfv36aekff/xx9u3bx4svvsjOnTv58MMPmTNnDs8999zVKP5fU97peBs3biw++uijEuv37t0rAPHGG2/o1i9fvlwApS779+/X0h04cEDceeedws/PT0RERIh//etfwu12a9tff/11UbVqVWGz2URYWJho3bq1+OWXX0qU4/333xeVK1cWFotFNG7cWPz++++67Q8//LBo1arVec9v//79AhCbNm06b5r4+HgxZsyY824XQojx48eLiIgIERgYKB5++GHx4osvinr16unSzJkzRyQlJQmLxSJq164tFi5cqNs+ffr0Uq9b8WM//PDDwm63X7BOAHH69Glt/dSpU89bJ2azWdx0001i+vTpJeqkbdu2Ii4uTru2Tz75pK5OGjZsKAICAoTD4dCV459WJxEREaJatWoljl9UH4899piuTi50j5y7VKpUSXePTJ48Wbu2cXFxIjY2VnePvP/++yIkJERXJ1eqPvLz80VoaKh4/fXXdedV/D4/V3p6uujSpYuwWq2icuXK4osvvhDx8fHinXfe0dI4nU4xZMgQERoaKvz9/cU999wj0tPTdfm0atXqoq8xgOjXr99566VRo0aie/fu2vry1EtiYqKuXsaNGydiY2OFv7+/qFy5sqhUqZKuXiZOnCh+/vln4XQ6fQdTVXH8yH6xJfl3sfH3VSJ1S7LIzTwuhCtPW/anbRdp2zbp1hVfsk+li72pW7U8tmxYK3ZtTxE5mRlamoKcTJG89lfdOqGquuvh8XjE3r17RXJyskhJSRHp6eli586d4uDBg+LBBx8UDzzwgFBVVRw5ckSkpKSIDRs2iGeffVbUqVNHCCHEoEGDRNeuXcW+ffvE+vXrxeuvvy4A8emnn4r169eLnJwcsWPHDnHixAmxefNmUaVKFdGzZ08hhBAFBQUCEJMmTRK7d+8WW7ZsEdu2bRM5OTli/fr1Yv369aJLly6iVatW2uPMzEzt76IlJiZGPP/88+LQoUPC6XRq65cuXSoURRFPP/20WL9+vWjXrp3o06ePEEKIU6dOia1bt4qUlBQBiCVLlogNGzaIW2+9VQwZMkR3jSpVqiRGjhypWweI+fPn69YVXYPMzMxS1//xxx/i7bffFu3btxcWi0V8/fXXYv369WLhwoUCEBs3bhR79uwROTk5JeonJiZGvPDCC7r6KXJu/ezcuVM4nU6xb98+YTKZxGeffSb27dsnqlWrJpo0aaK7dkXH+uqrrwQgfvzxRyGEEGPGjCnxenn06FGxbds2IYTvtTE4OFhkZGSIzZs3a2mKXi++/vprsWHDBrFjxw6Rm5ury8fpdIrdu3cLq9UqXn/9dbFt2zZx6tQpXZqi+rncnE6n2LFjx5/3onRNutD7VqtWrcTDDz+sS3+x93Lp8itPHcXHx1/0s5R0ZZT3Xiru4Ycf1n1Okq6c8tbTmjVrRJMmTYTVahU33XSTGD9+vPB4PH9zqf9ZylNHbrdbjB07VvveHBcXJ4YMGaL7fi5dfuf7LldUN6V9512+fLmoX7++sFgsWkzkelTuIN8PP/wgatasKbxer279r7/+Ksxms8jIyLhshbsSWrZs+Zc+ROTn5wubzSaWL19+2cr0V7Rs2VI88MAD10Sd9OrVS4wfP77c+91odVK7dm0RERFx1etDiEurk79aH0U+++wzkZiYKAoLC/9yXn/Vvn37hMFgEFWrVr0m6qVbt25i/fr15QospKamiqNHj/6l42ZnZ4uNGzfqfkApj//85z8lAj1C+AI5iqKIDRs2iJCQEDF79mxtW15enggLCxP33nuvtu706dNi69at4q233hKA9gU8JydHAOKbb745bxnK8iXj3EBxkVdeeUUYjUaxe/duIYQQL730kqhevbpQVVXs2LFDnDp1SnzwwQfCbrdrz5NWrVqJZ555RpdPxYoVxdixY3XrSgvylUfv3r3FnXfeKTZu3Ch+/vnnEj/OlPUcL0RVVREUFCTef/99IYQQEyZMEIqiiJSUFF06r9crbrnlFnHTTTeJ7OxsIUTpQb7iioJ85yrLjzRCCLFnzx4BiD179pS6vah+LjcZ5JMkSZIkSZJuJOUewbpLly7s3r2bo0ePEhcXh8vl4uTJk4wdO5aePXuWmHb4WpKdnc3evXtZuHDhJeexfPly2rZtS+vWrS9fwS5R8fP59NNPr2qdFBYWUrdu3XI3Z70R66RokoGrfY9cSp1cjvoosmjRIiZMmFCuGXevlEWLFvH4449TrVq1q14vp06don379roZbC/G4/Hgcrn+chmzs7OJiYm55MkLOnbsyMiRIzl9+rSuK2VCQgLNmzdn4MCBeL1eunXrpm0LCAjg448/pnfv3jz66KM89dRTBAUFsXDhQiZOnMjgwYPp1KkThYWFHDt2DDj/hA1FXC6XbtiCon2KzwCYm5tLRkYGbreb/fv38+WXX/Lpp58yceJEEhMTAd8M15MnT+bJJ5/kgQceIC0tjTFjxvD888+XGDuliMfjQQih64JbXk6nk2HDhnHfffdRpUoVjhw5wvr162nfvj0xMTFkZ2eXKZ+icyzO39+foKAgxo4di8PhoHPnzsTHx3PmzBnee+893G437du3B+C5555jwYIFdO3albfeeosmTZpw/PhxJkyYQGpqKtOnT9d1jy3qCl+c3W6natWqFy1rZmZmibKGhIRo41yuWrWKm266qdS83G43oaGhuu70kiRJkiRJkiSV4q9GCadPny4MBoNo2LChOHLkyGWIO0p/layTa4usj2vT1ayX67n10PmGbPjwww/P2yVaCF+LyY4dO4qgoCCtuXxR1+6TJ0+K9evXi+3bt1+0RdzDDz9catP76tWra2mKdwWzWCyicuXKolevXqUO8bBixQpx6623CovFIqKjo8Xw4cN1LR1La8lXWiu6c8t9oSEEXC6X6N27tzb8QcWKFcVTTz2lPR+KuhdcrCVfadfhscceE0II8csvv4gePXpox4iKihKdOnUSq1at0uWTn58vXn75ZZGYmCjMZrMICwsTPXr0KNE1dsyYMaUe74477hBCXLwlX2nLrFmztHQdOnQQEydOPO/5XinX870oSZIkSZIkSedShJBTukiSJP2dCgoK2L9/P1WqVCkxY++1buHChQwbNoxt27adt7XbxRQUFNC9e3cOHz7MypUrqVChwmUu5dXlcDgIDw9n8eLF10QL42vd9u3badu2rTbL8t/per4XJUmSJEmSJOlcl/YNTZIkSfpH6tKlC48++ihHjx695DxsNhsLFiygX79+/Prrr5exdNeGa2kIgetBeno6X3zxxd8e4JMkSZIkSZKkG41sySdJkvQ3k62HJOnaIO9FSZIkSZIk6UYiW/JJkiRJkiRJkiRJkiRJ0nVOBvkkSZIkSZIkSZIkSZIk6Tong3ySJEmSJEmSJEmSJEmSdJ2TQT5Juo4MHDiQunXrUlhYqFu/aNEiLBYLGzduvEol0zt58iRPPPEElStXxmq1Eh0dTceOHVm9evXVLtoVlZCQgKIoKIqCn58fCQkJ9OrV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fWPyVTt2WUVERHD69OkS6/v06cPMmTMZMWIEM2fOpFOnToSHhwN/tlBLTU2lefPmJfZNTU2lfv36unXvvPMO7dq1Izg4mAoVKpTYJyAggMTExDKXu0hmZiYnT57UjS1XFud2o1UURbeuKEhYPMh1MWPHjuXBBx9k4cKFLF68mDFjxjB79mzuueceLc2qVasICgoiMjISu91eIo+IiIiLXoeqVatStWpVBg0axMsvv0xSUhJff/01AwYMAHxjDi5fvpybb76ZatWqERkZCaB12RVCkJiYSFxcHAA//vgjR48e5f7779cdx+v1smzZMtq3b6+tCw8Pp2fPnvTs2ZMJEybQoEED3nzzTWbMmFHm65SVlQVQ6vNAkiRJkiRJkiQ92ZJPkiTpKlMUBYO//1VZirdiu5gGDRqwY8eOEusffPBBtm3bRnJyMnPnzqVPnz7ato4dOxIWFsZbb71VYr/vvvuO3bt3079/f9366OhoEhMTL3tg591338VgMHD33XcDvi7Ea9eu1bUyXL16NXa7ndjY2Mt67NIkJSXx3HPP8dNPP3Hvvfcyffp03fYqVapQtWrVUgN8lyIhIQF/f3/y8/O1dW3atGHNmjUsXbqU1q1ba+tbtmzJihUrWLFihW48vmnTptG7d+8SLQh79+5dYgKO4iwWC1WrVtUduyy2bdtGbGwsERER5dpPkiRJkiRJkv6JZEs+SZIkqUw6duzIyJEjOX36tG4224SEBJo3b87AgQPxer1069ZN2xYQEMDHH39M7969efTRR3nqqacICgpi2bJlDBs2jMGDB9O5c+dylcPlcpGRkaFbZzKZdIGg3NxcMjIycLvd7N+/ny+//JJPP/2UiRMnaq3fhgwZwuTJkxk6dChPPfUUaWlpjBkzhueff14bj+9KcDqdDBs2jPvuu48qVapw5MgR1q9fT48ePcqVT9E5Fufv709QUBBjx47F4XDQuXNn4uPjOXPmDO+99x5ut1vX2q5oXL7PPvuMqVOnautbtWqljcM3ZMgQAE6ePMn333/Pd999R506dXTH7devH/fccw9ZWVmsWbOG2bNn07t3b5KSkhBC8P3337No0aISgcyLWbVqFR06dCjXPpIkSZIkSZL0TyVb8kmSJEllUrduXRo2bMicOXNKbOvTpw+bN2/mnnvu0cZRK3LfffexfPlyDh06xO23306VKlUY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li1jge8RNTU1ITk5+Qcv8BERERER/dywk4+I6EfG7iGinwb+FomIiIjo54SdfERERERERERERJMci3xERERERERERESTHIt8REREREREREREkxyLfERERERERERERJMci3xERERERERERESTHIt8REREREREREREkxyLfERERERERERERJMci3xERKSzzs5OWFtb49q1axOdCj0Bnn/+eRQWFk50GkREREREkwKLfEREpLMDBw5g7dq1cHZ2Htd2n3/+OYKCgjBt2jQYGxvDy8sLWVlZuHfvnihOIpEIw8LCAn5+fvj73/8urG/btk0UMzRWrFghxDg7OwvzJiYmcHZ2xqZNm0T7+SlTq9Wic5sxYwaCg4Pxr3/9S4gZfo7DR3p6OgDA1tZW+PcQlUoFiUQCtVotml+6dCnCwsIAAEePHoWlpaWwdvToUa3rCwD/+c9/RtzXyZMnoVAoYGZmhqlTp2LhwoU4evSoKObatWuQSCSwtraGRqMRrXl7eyM1NVX4vHfvXqhUKgwMDDzsshERERERPfFY5CMiIp10d3cjNzcX4eHh49ruxIkTUCgUcHBwQElJCS5duoTY2Fjs378fmzdvxuDgoCj+yJEjaGtrQ3l5OWQyGVatWiUqcK1YsQJtbW2i8cknn4j28cYbb6CtrQ2XL1/GH//4R1haWiIgIAAHDhx49AvwI7t8+TJaW1vxl7/8BV9//TVWr14tKooOnePwERMTA+B+4e7BAlxJSQkcHR1F8729vfjHP/6BZcuWjZqHgYEB/va3v6GkpGTMfA8dOoS1a9fCz88PlZWVuHDhAjZv3ozo6Gj85je/0YrXaDTIyMgYc58rV66ERqNBcXHxmHFERERERMQiHxER6ej06dOYMmUKnn/+eQDAwMAAHBwckJ2dLYqrqamBnp4eGhsb0dXVhcjISKxZswY5OTnw9vaGs7MzIiIicOzYMRQUFOD48eOi7S0tLWFjY4M5c+YgOzsbPT09+Otf/yqsT5kyBTY2NqIxbdo00T7MzMxgY2MDJycn+Pv7IycnB6+//jpSUlJw+fJlIa60tBSLFi3ClClTYGtrC5VKhe+++05YX7p0KWJiYhAXF4dp06ZhxowZ+P3vf4+uri68/PLLMDMzg5ub27iLULW1tVAqlTAzM4O5uTnmz5+Pf/7zn6IYa2tr2Nrawt/fHykpKbh48SK+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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "#vQPEDom\n", + "y2020_PEDom = d_vars['vQPEDom'][(d_vars['vQPEDom'].sYear=='y2020')]\n", + "y2025_PEDom = d_vars['vQPEDom'][(d_vars['vQPEDom'].sYear=='y2025')]\n", + "y2030_PEDom = d_vars['vQPEDom'][(d_vars['vQPEDom'].sYear=='y2030')]\n", + "y2035_PEDom = d_vars['vQPEDom'][(d_vars['vQPEDom'].sYear=='y2035')]\n", + "y2040_PEDom = d_vars['vQPEDom'][(d_vars['vQPEDom'].sYear=='y2040')]\n", + "y2045_PEDom = d_vars['vQPEDom'][(d_vars['vQPEDom'].sYear=='y2045')]\n", + "y2050_PEDom = d_vars['vQPEDom'][(d_vars['vQPEDom'].sYear=='y2050')]\n", + "\n", + "# Drop all data that is not related to the primary energy domestic capacity: sPENUCLE,sPEIMPCO,sPENAGAS,sPELNGAS,sPECROIL\n", + "y2020_PEDom = y2020_PEDom[~y2020_PEDom.sPE.str.startswith('sPENUCLE')]\n", + "y2020_PEDom = y2020_PEDom[~y2020_PEDom.sPE.str.startswith('sPEIMPCO')]\n", + "y2020_PEDom = y2020_PEDom[~y2020_PEDom.sPE.str.startswith('sPENAGAS')]\n", + "y2020_PEDom = y2020_PEDom[~y2020_PEDom.sPE.str.startswith('sPELNGAS')]\n", + "y2020_PEDom = y2020_PEDom[~y2020_PEDom.sPE.str.startswith('sPECROIL')]\n", + "\n", + "y2025_PEDom = y2025_PEDom[~y2025_PEDom.sPE.str.startswith('sPENUCLE')]\n", + "y2025_PEDom = y2025_PEDom[~y2025_PEDom.sPE.str.startswith('sPEIMPCO')]\n", + "y2025_PEDom = y2025_PEDom[~y2025_PEDom.sPE.str.startswith('sPENAGAS')]\n", + "y2025_PEDom = y2025_PEDom[~y2025_PEDom.sPE.str.startswith('sPELNGAS')]\n", + "y2025_PEDom = y2025_PEDom[~y2025_PEDom.sPE.str.startswith('sPECROIL')]\n", + "y2030_PEDom = y2030_PEDom[~y2030_PEDom.sPE.str.startswith('sPENUCLE')]\n", + "y2030_PEDom = y2030_PEDom[~y2030_PEDom.sPE.str.startswith('sPEIMPCO')]\n", + "y2030_PEDom = y2030_PEDom[~y2030_PEDom.sPE.str.startswith('sPENAGAS')]\n", + "y2030_PEDom = y2030_PEDom[~y2030_PEDom.sPE.str.startswith('sPELNGAS')]\n", + "y2030_PEDom = y2030_PEDom[~y2030_PEDom.sPE.str.startswith('sPECROIL')]\n", + "y2035_PEDom = y2035_PEDom[~y2035_PEDom.sPE.str.startswith('sPENUCLE')]\n", + "y2035_PEDom = y2035_PEDom[~y2035_PEDom.sPE.str.startswith('sPEIMPCO')]\n", + "y2035_PEDom = y2035_PEDom[~y2035_PEDom.sPE.str.startswith('sPENAGAS')]\n", + "y2035_PEDom = y2035_PEDom[~y2035_PEDom.sPE.str.startswith('sPELNGAS')]\n", + "y2035_PEDom = y2035_PEDom[~y2035_PEDom.sPE.str.startswith('sPECROIL')]\n", + "y2040_PEDom = y2040_PEDom[~y2040_PEDom.sPE.str.startswith('sPENUCLE')]\n", + "y2040_PEDom = y2040_PEDom[~y2040_PEDom.sPE.str.startswith('sPEIMPCO')]\n", + "y2040_PEDom = y2040_PEDom[~y2040_PEDom.sPE.str.startswith('sPENAGAS')]\n", + "y2040_PEDom = y2040_PEDom[~y2040_PEDom.sPE.str.startswith('sPELNGAS')]\n", + "y2040_PEDom = y2040_PEDom[~y2040_PEDom.sPE.str.startswith('sPECROIL')]\n", + "y2045_PEDom = y2045_PEDom[~y2045_PEDom.sPE.str.startswith('sPENUCLE')]\n", + "y2045_PEDom = y2045_PEDom[~y2045_PEDom.sPE.str.startswith('sPEIMPCO')]\n", + "y2045_PEDom = y2045_PEDom[~y2045_PEDom.sPE.str.startswith('sPENAGAS')]\n", + "y2045_PEDom = y2045_PEDom[~y2045_PEDom.sPE.str.startswith('sPELNGAS')]\n", + "y2045_PEDom = y2045_PEDom[~y2045_PEDom.sPE.str.startswith('sPECROIL')]\n", + "y2050_PEDom = y2050_PEDom[~y2050_PEDom.sPE.str.startswith('sPENUCLE')]\n", + "y2050_PEDom = y2050_PEDom[~y2050_PEDom.sPE.str.startswith('sPEIMPCO')]\n", + "y2050_PEDom = y2050_PEDom[~y2050_PEDom.sPE.str.startswith('sPENAGAS')]\n", + "y2050_PEDom = y2050_PEDom[~y2050_PEDom.sPE.str.startswith('sPELNGAS')]\n", + "y2050_PEDom = y2050_PEDom[~y2050_PEDom.sPE.str.startswith('sPECROIL')]\n", + "\n", + "\n", + "\n", + "# set index to sPE, sYear, sSeason, sDay, sHour and the values to vQPEImp and unstack the table\n", + "y2020_PEDom = y2020_PEDom.set_index(['sPE', 'sYear', 'sSeason', 'sDay', 'sHour'])\n", + "y2025_PEDom = y2025_PEDom.set_index(['sPE', 'sYear', 'sSeason', 'sDay', 'sHour'])\n", + "y2030_PEDom = y2030_PEDom.set_index(['sPE', 'sYear', 'sSeason', 'sDay', 'sHour'])\n", + "y2035_PEDom = y2035_PEDom.set_index(['sPE', 'sYear', 'sSeason', 'sDay', 'sHour'])\n", + "y2040_PEDom = y2040_PEDom.set_index(['sPE', 'sYear', 'sSeason', 'sDay', 'sHour'])\n", + "y2045_PEDom = y2045_PEDom.set_index(['sPE', 'sYear', 'sSeason', 'sDay', 'sHour'])\n", + "y2050_PEDom = y2050_PEDom.set_index(['sPE', 'sYear', 'sSeason', 'sDay', 'sHour'])\n", + "\n", + "# Graph 7 SUBPLOTS the results with the index as x-axis and the values of vQPEImp as y-axis.\n", + "# Put the corresponding title to each subplot\n", + "\n", + "fig, axs = plt.subplots(4, 2, figsize=(15, 15))\n", + "fig.suptitle('Primary Energy Domestic Capacity', fontsize=16)\n", + "y2020_PEDom.unstack('sPE').plot(ax=axs[0, 0], title='2020', legend=True)\n", + "y2025_PEDom.unstack('sPE').plot(ax=axs[0, 1], title='2025', legend=True)\n", + "y2030_PEDom.unstack('sPE').plot(ax=axs[1, 0], title='2030', legend=True)\n", + "y2035_PEDom.unstack('sPE').plot(ax=axs[1, 1], title='2035', legend=True)\n", + "y2040_PEDom.unstack('sPE').plot(ax=axs[2, 0], title='2040', legend=True)\n", + "y2045_PEDom.unstack('sPE').plot(ax=axs[2, 1], title='2045', legend=True)\n", + "y2050_PEDom.unstack('sPE').plot(ax=axs[3, 0], title='2050', legend=True)\n", + "\n", + "# Dont show x axis labels for the first 7 subplots\n", + "for ax in axs.flat:\n", + " ax.label_outer()\n", + "\n", + "# Add a legend for all images\n", + "plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# vTotalCost\n", + "y2020=d_vars['vTotalCost'][(d_vars['vTotalCost'].sYear=='y2020')].vTotalCost.sum()\n", + "y2025=d_vars['vTotalCost'][(d_vars['vTotalCost'].sYear=='y2025')].vTotalCost.sum()\n", + "y2030=d_vars['vTotalCost'][(d_vars['vTotalCost'].sYear=='y2030')].vTotalCost.sum()\n", + "y2035=d_vars['vTotalCost'][(d_vars['vTotalCost'].sYear=='y2035')].vTotalCost.sum()\n", + "y2040=d_vars['vTotalCost'][(d_vars['vTotalCost'].sYear=='y2040')].vTotalCost.sum()\n", + "y2045=d_vars['vTotalCost'][(d_vars['vTotalCost'].sYear=='y2045')].vTotalCost.sum()\n", + "y2050=d_vars['vTotalCost'][(d_vars['vTotalCost'].sYear=='y2050')].vTotalCost.sum()\n", + "\n", + "y2020opcost=d_vars['vOpCost'][(d_vars['vOpCost'].sYear=='y2020')].vOpCost.sum()\n", + "y2025opcost=d_vars['vOpCost'][(d_vars['vOpCost'].sYear=='y2025')].vOpCost.sum()\n", + "y2030opcost=d_vars['vOpCost'][(d_vars['vOpCost'].sYear=='y2030')].vOpCost.sum()\n", + "y2035opcost=d_vars['vOpCost'][(d_vars['vOpCost'].sYear=='y2035')].vOpCost.sum()\n", + "y2040opcost=d_vars['vOpCost'][(d_vars['vOpCost'].sYear=='y2040')].vOpCost.sum()\n", + "y2045opcost=d_vars['vOpCost'][(d_vars['vOpCost'].sYear=='y2045')].vOpCost.sum()\n", + "y2050opcost=d_vars['vOpCost'][(d_vars['vOpCost'].sYear=='y2050')].vOpCost.sum()\n", + "\n", + "y2020invCE=d_vars['vInvCostCE'][(d_vars['vInvCostCE'].sYear=='y2020')].vInvCostCE.sum()\n", + "y2025invCE=d_vars['vInvCostCE'][(d_vars['vInvCostCE'].sYear=='y2025')].vInvCostCE.sum()\n", + "y2030invCE=d_vars['vInvCostCE'][(d_vars['vInvCostCE'].sYear=='y2030')].vInvCostCE.sum()\n", + "y2035invCE=d_vars['vInvCostCE'][(d_vars['vInvCostCE'].sYear=='y2035')].vInvCostCE.sum()\n", + "y2040invCE=d_vars['vInvCostCE'][(d_vars['vInvCostCE'].sYear=='y2040')].vInvCostCE.sum()\n", + "y2045invCE=d_vars['vInvCostCE'][(d_vars['vInvCostCE'].sYear=='y2045')].vInvCostCE.sum()\n", + "y2050invCE=d_vars['vInvCostCE'][(d_vars['vInvCostCE'].sYear=='y2050')].vInvCostCE.sum()\n", + "\n", + "# InvCostST\n", + "# Now lets graph the investment costs for supply technologies\n", + "y2020invST = d_vars['vInvCostST'][(d_vars['vInvCostST'].sYear=='y2020')].vInvCostST.sum()\n", + "y2025invST = d_vars['vInvCostST'][(d_vars['vInvCostST'].sYear=='y2025')].vInvCostST.sum()\n", + "y2030invST = d_vars['vInvCostST'][(d_vars['vInvCostST'].sYear=='y2030')].vInvCostST.sum()\n", + "y2035invST = d_vars['vInvCostST'][(d_vars['vInvCostST'].sYear=='y2035')].vInvCostST.sum()\n", + "y2040invST = d_vars['vInvCostST'][(d_vars['vInvCostST'].sYear=='y2040')].vInvCostST.sum()\n", + "y2045invST = d_vars['vInvCostST'][(d_vars['vInvCostST'].sYear=='y2045')].vInvCostST.sum()\n", + "y2050invST = d_vars['vInvCostST'][(d_vars['vInvCostST'].sYear=='y2050')].vInvCostST.sum()\n", + "\n", + "\n", + "\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "\n", + "#visualize the results\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "TotalCost = [y2020, y2025, y2030, y2035, y2040, y2045, y2050]\n", + "OperationalCost = [1e-3*y2020opcost, 1e-3*y2025opcost, 1e-3*y2030opcost, 1e-3*y2035opcost, 1e-3*y2040opcost, 1e-3*y2045opcost, 1e-3*y2050opcost]\n", + "TotalInvCE = [y2020invCE, y2025invCE, y2030invCE, y2035invCE, y2040invCE, y2045invCE, y2050invCE]\n", + "TotalInvST = [y2020invST, y2025invST, y2030invST, y2035invST, y2040invST, y2045invST, y2050invST]\n", + "\n", + "\n", + "plt.figure(figsize=(10, 5))\n", + "plt.plot(years, TotalCost,marker='o')\n", + "plt.plot(years, OperationalCost,marker='o')\n", + "plt.plot(years, TotalInvCE,marker='o')\n", + "plt.plot(years, TotalInvST,marker='o')\n", + "plt.title('Total Cost per Year')\n", + "plt.legend(['Total Cost', 'Operational Cost', 'Total Inv CE', 'Total Inv ST'])\n", + "plt.xlabel('Year')\n", + "plt.ylabel('Total Cost [GEuro]')\n", + "plt.grid()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'y2020' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[12], line 6\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mnumpy\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01mnp\u001b[39;00m\n\u001b[0;32m 5\u001b[0m years \u001b[38;5;241m=\u001b[39m [\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m2020\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m2025\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m2030\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m2035\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m2040\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m2045\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m2050\u001b[39m\u001b[38;5;124m'\u001b[39m]\n\u001b[1;32m----> 6\u001b[0m TotalCost \u001b[38;5;241m=\u001b[39m [\u001b[43my2020\u001b[49m, y2025, y2030, y2035, y2040, y2045, y2050]\n\u001b[0;32m 7\u001b[0m OperationalCost \u001b[38;5;241m=\u001b[39m [\u001b[38;5;241m1e-3\u001b[39m\u001b[38;5;241m*\u001b[39my2020opcost, \u001b[38;5;241m1e-3\u001b[39m\u001b[38;5;241m*\u001b[39my2025opcost, \u001b[38;5;241m1e-3\u001b[39m\u001b[38;5;241m*\u001b[39my2030opcost, \u001b[38;5;241m1e-3\u001b[39m\u001b[38;5;241m*\u001b[39my2035opcost, \u001b[38;5;241m1e-3\u001b[39m\u001b[38;5;241m*\u001b[39my2040opcost, \u001b[38;5;241m1e-3\u001b[39m\u001b[38;5;241m*\u001b[39my2045opcost, \u001b[38;5;241m1e-3\u001b[39m\u001b[38;5;241m*\u001b[39my2050opcost]\n\u001b[0;32m 8\u001b[0m TotalInvCE \u001b[38;5;241m=\u001b[39m [y2020invCE, y2025invCE, y2030invCE, y2035invCE, y2040invCE, y2045invCE, y2050invCE]\n", + "\u001b[1;31mNameError\u001b[0m: name 'y2020' is not defined" ] } ], "source": [ - "data = openMASTER.load_dataportal_from_excel('../data/input/openMASTER_Data.xlsx')\n", - "#data = openMASTER.load_dataportal_from_csv()" + "# Use the same data as before but now we will plot the results in a stacked bar plot without the variable TotalCost\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "TotalCost = [y2020, y2025, y2030, y2035, y2040, y2045, y2050]\n", + "OperationalCost = [1e-3*y2020opcost, 1e-3*y2025opcost, 1e-3*y2030opcost, 1e-3*y2035opcost, 1e-3*y2040opcost, 1e-3*y2045opcost, 1e-3*y2050opcost]\n", + "TotalInvCE = [y2020invCE, y2025invCE, y2030invCE, y2035invCE, y2040invCE, y2045invCE, y2050invCE]\n", + "TotalInvST = [y2020invST, y2025invST, y2030invST, y2035invST, y2040invST, y2045invST, y2050invST]\n", + "\n", + "plt.figure(figsize=(10, 5))\n", + "plt.plot(years, TotalCost, 'ko-')\n", + "plt.bar(years, OperationalCost)\n", + "plt.bar(years, TotalInvCE, bottom=OperationalCost)\n", + "plt.bar(years, TotalInvST, bottom=np.array(OperationalCost)+np.array(TotalInvCE))\n", + "plt.title('Total Cost per Year')\n", + "plt.legend(['Total Cost','Operational Cost', 'Total Inv CE', 'Total Inv ST'])\n", + "plt.xlabel('Year')\n", + "plt.ylabel('Total Cost [GEuro]')\n", + "plt.grid()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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x8fXeJ1HH31UvfLKK23fP/PMM+pll11m1+a2225Thw0b5uBXICqrrz4t/8VS8ZeNaBiO6tOZM2eqUVFRtu/lfepc9dWv8l51novp0w8++EAdNGiQumzZsir9J+9V56qvfpX3qvNcaJ8C6q+//lrjdV3pvSpTIt1IdnY2AMHBwQBs3bqVkpIShgwZYmvToUMHmjdvTnx8/DmvU34NgPj4eLtrAAwbNuyc1xCOUV99Wq5r165ERkZyzTXXsG7dOgdHL6rjiD49ffo0v/zyC4MGDbLtk/epc9VXv5aT92rDu9A+3bt3L1OnTuXLL79Ep6v6Z5a8V52rvvq1nLxXG97F/PwdN24coaGh9OrVi88//xy1wvLUrvRelYTNTVitViZOnEi/fv3o1KkTAMnJyZhMJgIDA+3ahoeH1zinev369Xz//fc8/PDDtn3JycmEh4dXuYbZbKagoMCxL0TY1GefRkZGMmfOHH7++Wd+/vlnoqOjGTx4MNu2bau31yMuvk/vuOMOvL29adasGf7+/nz66ae2Y/I+dZ767Fd5rzrHhfZpUVERd9xxB2+99RbNmzev9tryXnWe+uxXea86x8X8/J06dSo//PADS5Ys4eabb+bRRx9l1qxZtuOu9F41NOiziXozbtw4du/ezdq1ay/4Grt37+b666/nxRdfZOjQoQ6MTlyI+uzT9u3b0759e9v3ffv25ciRI7z77rv873//u6i4Rc0utk/fffddXnzxRQ4ePMiUKVOYNGkSH3zwgYOjFHVVn/0q71XnuNA+nTJlCh07duSuu+6qp8jExajPfpX3qnNczM/ff//737bHV1xxBXl5ebz11ltMmDDBkSE6hIywuYHx48czf/58VqxYQVRUlG1/REQExcXFVapTpaSkEBERYbdv7969XH311Tz88MM8//zzdsciIiKqVNZJSUnB398fLy8vx74YAdR/n1anV69eHD582CHxi6oc0acRERF06NCB0aNH89FHH/Hhhx+SlJRkOybv04ZX3/1aHXmv1q+L6dPly5fz448/YjAYMBgMXH311QCEhoby4osv2q4j79WGV9/9Wh15r9YvR/z8rah3796cPHmSoqIi23Vc5b0qCVsjpqoq48eP59dff2X58uXExMTYHe/evTtGo5Fly5bZ9h04cIATJ04QFxdn27dnzx6uvPJKxowZw6uvvlrleeLi4uyuAbBkyRK7awjHaKg+rc727duJjIx0zAsRNo7q08qsViuA7ReLvE8bVkP1a3XkvVo/HNGnP//8Mzt27GD79u1s377dNr11zZo1jBs3DpD3akNrqH6tjrxX60d9/fzdvn07QUFBeHh4AC72Xm3wMifCYcaOHasGBASoK1eutCtJmp+fb2vzyCOPqM2bN1eXL1+ubtmyRY2Li1Pj4uJsx3ft2qU2adJEveuuu+yukZqaamtTXtb06aefVvft26e+//77UoK4njRUn7777rvqvHnz1EOHDqm7du1SH3/8cVWn06lLly5t0Nd7KXBEny5YsED9/PPP1V27dqkJCQnq/Pnz1Y4dO6r9+vWztZH3acNqqH6V92rDcUSfVlZd5UB5rzashupXea82HEf06e+//65+8skn6q5du9RDhw6pH3zwgert7a2+8MILtjau9F6VhK0RA6rd5s6da2tTUFCgPvroo2pQUJDq7e2t3njjjWpSUpLt+IsvvljtNVq0aGH3XCtWrFC7du2qmkwmtVWrVnbPIRynofp02rRpauvWrVVPT081ODhYHTx4sLp8+fIGfKWXDkf06fLly9W4uDg1ICBA9fT0VNu2bas+++yzVcpHy/u04TRUv8p7teE4ok8rq6nUu7xXG05D9au8VxuOI/r0zz//VLt27ar6+vqqPj4+apcuXdQ5c+ZUWTfPVd6riqpWqF8phBBCCCGEEMJlyD1sQgghhBBCCOGiJGETQgghhBBCCBclCZsQQgghhBBCuChJ2IQQQgghhBDCRUnCJoQQQgghhBAuShI2IYQQQgghhHBRkrAJIYQQQgghhIuShE0IIYQQQgghXJQkbEIIIYQQQgjhoiRhE0IIIS6QqqoMGTKEYcOGVTn2wQcfEBgYyMmTJ50QmRBCCHchCZsQQghxgRRFYe7cuWzcuJGPPvrItj8hIYFnnnmGWbNmERUV5dDnLCkpcej1hBD/3879g6QWxnEY/3pwEJIwpCJBOjVE4SkwGos2IUiQNoeCKGho6A9BW0tTRFBrzkENZ8/FhmqKoKgGKekQTWFCIASReYfLlRuN95rvvTwfONN5z+H3TvLgywHMRrABAPAHotGodnZ2tLKyovv7e1WrVc3MzCiRSCgej2tsbEzBYFDt7e2anJxUsVisPXt4eKjh4WGFQiGFw2GNj4+rUCjU7nueJ5/Pp4ODA42OjioQCGhvb68R2wQANIivWq1WGz0EAAD/ulQqpZeXF01MTGh9fV03NzeKxWKanZ3V1NSUXl9ftbq6qvf3d+VyOUmS67ry+XwaGBhQuVzW2tqaPM/TxcWFLMuS53nq6uqSbdva2tpSPB5XIBBQR0dHg3cLAPguBBsAAH/B09OTYrGYSqWSXNfV9fW1jo+Plc1ma2seHx8VjUaVz+fV09Pz5R3FYlGtra26urqS4zi1YNve3tbCwsJ3bgcAYAiORAIA8Be0tbVpbm5OfX19SqVSury81NHRkYLBYO3q7e2VpNqxx9vbW6XTaXV3d6u5uVm2bUuSHh4ePr17aGjoW/cCADCHv9EDAADwv/D7/fL7f/60lstlJZNJbWxsfFn360hjMplUZ2enMpmMIpGIPj4+5DiO3t7ePq1vamqq//AAACMRbAAA1MHg4KBc15Vt27WI+93z87Py+bwymYxGRkYkSScnJ989JgDAcByJBACgDubn51UqlZROp3V2dqZCoaBsNqvp6WlVKhW1tLQoHA5rd3dXd3d3yuVyWl5ebvTYAADDEGwAANRBJBLR6empKpWKEomE+vv7tbi4qFAoJMuyZFmW9vf3dX5+LsdxtLS0pM3NzUaPDQAwDF+JBAAAAABD8Q8bAAAAABiKYAMAAAAAQxFsAAAAAGAogg0AAAAADEWwAQAAAIChCDYAAAAAMBTBBgAAAACGItgAAAAAwFAEGwAAAAAYimADAAAAAEMRbAAAAABgqB+M+2V/15oJjgAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# vOpCost\n", + "# lets graph the operational costs\n", + "import pandas as pd\n", + "pPECost = pd.DataFrame(list(data['pPECost'].items()),columns = ['sPE','pPECost'])\n", + "pCEFixom = pd.DataFrame(list(data['pCEFixom'].items()),columns = ['sCE','pCEFixom'])\n", + "pSTFixom = pd.DataFrame(list(data['pSTFixom'].items()),columns = ['sST','pSTFixom'])\n", + "pSTVarom = pd.DataFrame(list(data['pSTVarom'].items()),columns = ['sST','pSTVarom'])\n", + "pESNSCost = data['pESNSCost']\n", + "\n", + "pPECost[['sPE', 'sYear']] = pd.DataFrame(pPECost['sPE'].tolist(), index=pPECost.index)\n", + "pSTVarom[['sST', 'sES']] = pd.DataFrame(pSTVarom['sST'].tolist(), index=pSTVarom.index)\n", + "pPECost = pPECost.set_index('sPE')\n", + "pCEFixom = pCEFixom.set_index('sCE')\n", + "pSTFixom = pSTFixom.set_index('sST')\n", + "pSTVarom = pSTVarom.set_index(['sST','sES'])\n", + "\n", + "YrGap = data['pYrGap']\n", + "DisRate = data['pDisRate'] \n", + "\n", + "y2020opcost=d_vars['vOpCost'][(d_vars['vOpCost'].sYear=='y2020')].vOpCost.sum()\n", + "y2025opcost=d_vars['vOpCost'][(d_vars['vOpCost'].sYear=='y2025')].vOpCost.sum()\n", + "y2030opcost=d_vars['vOpCost'][(d_vars['vOpCost'].sYear=='y2030')].vOpCost.sum()\n", + "y2035opcost=d_vars['vOpCost'][(d_vars['vOpCost'].sYear=='y2035')].vOpCost.sum()\n", + "y2040opcost=d_vars['vOpCost'][(d_vars['vOpCost'].sYear=='y2040')].vOpCost.sum()\n", + "y2045opcost=d_vars['vOpCost'][(d_vars['vOpCost'].sYear=='y2045')].vOpCost.sum()\n", + "y2050opcost=d_vars['vOpCost'][(d_vars['vOpCost'].sYear=='y2050')].vOpCost.sum()\n", + "\n", + "TotalCost_vQPEtoCE2020 = ((d_vars['vQPEImp'][(d_vars['vQPEImp'].sYear=='y2020')].groupby('sPE').sum().vQPEImp + d_vars['vQPEDom'][(d_vars['vQPEDom'].sYear=='y2020')].groupby('sPE').sum().vQPEDom))*(pPECost[pPECost.sYear=='y2020'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(1-1)))))\n", + "TotalCost_vQPEtoCE2025 = ((d_vars['vQPEImp'][(d_vars['vQPEImp'].sYear=='y2025')].groupby('sPE').sum().vQPEImp + d_vars['vQPEDom'][(d_vars['vQPEDom'].sYear=='y2025')].groupby('sPE').sum().vQPEDom))*(pPECost[pPECost.sYear=='y2025'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(2-1)))))\n", + "TotalCost_vQPEtoCE2030 = ((d_vars['vQPEImp'][(d_vars['vQPEImp'].sYear=='y2030')].groupby('sPE').sum().vQPEImp + d_vars['vQPEDom'][(d_vars['vQPEDom'].sYear=='y2030')].groupby('sPE').sum().vQPEDom))*(pPECost[pPECost.sYear=='y2030'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(3-1)))))\n", + "TotalCost_vQPEtoCE2035 = ((d_vars['vQPEImp'][(d_vars['vQPEImp'].sYear=='y2035')].groupby('sPE').sum().vQPEImp + d_vars['vQPEDom'][(d_vars['vQPEDom'].sYear=='y2035')].groupby('sPE').sum().vQPEDom))*(pPECost[pPECost.sYear=='y2035'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(4-1)))))\n", + "TotalCost_vQPEtoCE2040 = ((d_vars['vQPEImp'][(d_vars['vQPEImp'].sYear=='y2040')].groupby('sPE').sum().vQPEImp + d_vars['vQPEDom'][(d_vars['vQPEDom'].sYear=='y2040')].groupby('sPE').sum().vQPEDom))*(pPECost[pPECost.sYear=='y2040'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(5-1)))))\n", + "TotalCost_vQPEtoCE2045 = ((d_vars['vQPEImp'][(d_vars['vQPEImp'].sYear=='y2045')].groupby('sPE').sum().vQPEImp + d_vars['vQPEDom'][(d_vars['vQPEDom'].sYear=='y2045')].groupby('sPE').sum().vQPEDom))*(pPECost[pPECost.sYear=='y2045'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(6-1)))))\n", + "TotalCost_vQPEtoCE2050 = ((d_vars['vQPEImp'][(d_vars['vQPEImp'].sYear=='y2050')].groupby('sPE').sum().vQPEImp + d_vars['vQPEDom'][(d_vars['vQPEDom'].sYear=='y2050')].groupby('sPE').sum().vQPEDom))*(pPECost[pPECost.sYear=='y2050'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(7-1)))))\n", + "\n", + "TotalCEActive_FixomCost2020 = (d_vars['vCEActCap'][(d_vars['vCEActCap'].sYear=='y2020')].groupby('sCE').sum().vCEActCap)*(pCEFixom.pCEFixom)*(YrGap* (1/((1+DisRate)**(YrGap*(1-1)))))\n", + "TotalCEActive_FixomCost2025 = (d_vars['vCEActCap'][(d_vars['vCEActCap'].sYear=='y2025')].groupby('sCE').sum().vCEActCap)*(pCEFixom[pCEFixom.index.str.startswith('sCE')].pCEFixom)*(YrGap* (1/((1+DisRate)**(YrGap*(2-1)))))\n", + "TotalCEActive_FixomCost2030 = (d_vars['vCEActCap'][(d_vars['vCEActCap'].sYear=='y2030')].groupby('sCE').sum().vCEActCap)*(pCEFixom[pCEFixom.index.str.startswith('sCE')].pCEFixom)*(YrGap* (1/((1+DisRate)**(YrGap*(3-1)))))\n", + "TotalCEActive_FixomCost2035 = (d_vars['vCEActCap'][(d_vars['vCEActCap'].sYear=='y2035')].groupby('sCE').sum().vCEActCap)*(pCEFixom[pCEFixom.index.str.startswith('sCE')].pCEFixom)*(YrGap* (1/((1+DisRate)**(YrGap*(4-1)))))\n", + "TotalCEActive_FixomCost2040 = (d_vars['vCEActCap'][(d_vars['vCEActCap'].sYear=='y2040')].groupby('sCE').sum().vCEActCap)*(pCEFixom[pCEFixom.index.str.startswith('sCE')].pCEFixom)*(YrGap* (1/((1+DisRate)**(YrGap*(5-1)))))\n", + "TotalCEActive_FixomCost2045 = (d_vars['vCEActCap'][(d_vars['vCEActCap'].sYear=='y2045')].groupby('sCE').sum().vCEActCap)*(pCEFixom[pCEFixom.index.str.startswith('sCE')].pCEFixom)*(YrGap* (1/((1+DisRate)**(YrGap*(6-1)))))\n", + "TotalCEActive_FixomCost2050 = (d_vars['vCEActCap'][(d_vars['vCEActCap'].sYear=='y2050')].groupby('sCE').sum().vCEActCap)*(pCEFixom[pCEFixom.index.str.startswith('sCE')].pCEFixom)*(YrGap* (1/((1+DisRate)**(YrGap*(7-1)))))\n", + "\n", + "TotalSTCap_FixomCost2020 = (d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2020')].groupby('sST').sum().vSTTotCap)*pSTFixom[pSTFixom.index.str.startswith('sST')].pSTFixom\n", + "TotalSTCap_FixomCost2025 = (d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2025')].groupby('sST').sum().vSTTotCap)*pSTFixom[pSTFixom.index.str.startswith('sST')].pSTFixom\n", + "TotalSTCap_FixomCost2030 = (d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2030')].groupby('sST').sum().vSTTotCap)*pSTFixom[pSTFixom.index.str.startswith('sST')].pSTFixom\n", + "TotalSTCap_FixomCost2035 = (d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2035')].groupby('sST').sum().vSTTotCap)*pSTFixom[pSTFixom.index.str.startswith('sST')].pSTFixom\n", + "TotalSTCap_FixomCost2040 = (d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2040')].groupby('sST').sum().vSTTotCap)\n", + "TotalSTCap_FixomCost2045 = (d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2045')].groupby('sST').sum().vSTTotCap)\n", + "TotalSTCap_FixomCost2050 = (d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2050')].groupby('sST').sum().vSTTotCap) \n", + "\n", + "vQSTOUT_2020=pd.DataFrame(d_vars['vQSTOut'][d_vars['vQSTOut'].sYear=='y2020'].groupby(['sST','sES']).sum().vQSTOut)\n", + "vQSTOUT_2025=pd.DataFrame(d_vars['vQSTOut'][d_vars['vQSTOut'].sYear=='y2025'].groupby(['sST','sES']).sum().vQSTOut)\n", + "vQSTOUT_2030=pd.DataFrame(d_vars['vQSTOut'][d_vars['vQSTOut'].sYear=='y2030'].groupby(['sST','sES']).sum().vQSTOut)\n", + "vQSTOUT_2035=pd.DataFrame(d_vars['vQSTOut'][d_vars['vQSTOut'].sYear=='y2035'].groupby(['sST','sES']).sum().vQSTOut)\n", + "vQSTOUT_2040=pd.DataFrame(d_vars['vQSTOut'][d_vars['vQSTOut'].sYear=='y2040'].groupby(['sST','sES']).sum().vQSTOut)\n", + "vQSTOUT_2045=pd.DataFrame(d_vars['vQSTOut'][d_vars['vQSTOut'].sYear=='y2045'].groupby(['sST','sES']).sum().vQSTOut)\n", + "vQSTOUT_2050=pd.DataFrame(d_vars['vQSTOut'][d_vars['vQSTOut'].sYear=='y2050'].groupby(['sST','sES']).sum().vQSTOut)\n", + "\n", + "pSTVarom_ALIGNED=pSTVarom.reindex(vQSTOUT_2020.index)\n", + "TotalVaromSTCost_2020 = pSTVarom_ALIGNED['pSTVarom']*vQSTOUT_2020['vQSTOut']*YrGap* (1/((1+DisRate)**(YrGap*(1-1))))\n", + "TotalVaromSTCost_2025 = pSTVarom_ALIGNED['pSTVarom']*vQSTOUT_2025['vQSTOut']*YrGap* (1/((1+DisRate)**(YrGap*(2-1))))\n", + "TotalVaromSTCost_2030 = pSTVarom_ALIGNED['pSTVarom']*vQSTOUT_2030['vQSTOut']*YrGap* (1/((1+DisRate)**(YrGap*(3-1))))\n", + "TotalVaromSTCost_2035 = pSTVarom_ALIGNED['pSTVarom']*vQSTOUT_2035['vQSTOut']*YrGap* (1/((1+DisRate)**(YrGap*(4-1))))\n", + "TotalVaromSTCost_2040 = pSTVarom_ALIGNED['pSTVarom']*vQSTOUT_2040['vQSTOut']*YrGap* (1/((1+DisRate)**(YrGap*(5-1))))\n", + "TotalVaromSTCost_2045 = pSTVarom_ALIGNED['pSTVarom']*vQSTOUT_2045['vQSTOut']*YrGap* (1/((1+DisRate)**(YrGap*(6-1))))\n", + "TotalVaromSTCost_2050 = pSTVarom_ALIGNED['pSTVarom']*vQSTOUT_2050['vQSTOut']*YrGap* (1/((1+DisRate)**(YrGap*(7-1))))\n", + "\n", + "ESNSTotalCosts_2020=(d_vars['vQESNS'][d_vars['vQESNS'].sYear=='y2020'].groupby(['sST','sES']).sum().vQESNS).sum()*pESNSCost*YrGap* (1/((1+DisRate)**(YrGap*(1-1))))\n", + "ESNSTotalCosts_2025=(d_vars['vQESNS'][d_vars['vQESNS'].sYear=='y2025'].groupby(['sST','sES']).sum().vQESNS).sum()*pESNSCost*YrGap* (1/((1+DisRate)**(YrGap*(2-1))))\n", + "ESNSTotalCosts_2030=(d_vars['vQESNS'][d_vars['vQESNS'].sYear=='y2030'].groupby(['sST','sES']).sum().vQESNS).sum()*pESNSCost*YrGap* (1/((1+DisRate)**(YrGap*(3-1))))\n", + "ESNSTotalCosts_2035=(d_vars['vQESNS'][d_vars['vQESNS'].sYear=='y2035'].groupby(['sST','sES']).sum().vQESNS).sum()*pESNSCost*YrGap* (1/((1+DisRate)**(YrGap*(4-1))))\n", + "ESNSTotalCosts_2040=(d_vars['vQESNS'][d_vars['vQESNS'].sYear=='y2040'].groupby(['sST','sES']).sum().vQESNS).sum()*pESNSCost*YrGap* (1/((1+DisRate)**(YrGap*(5-1))))\n", + "ESNSTotalCosts_2045=(d_vars['vQESNS'][d_vars['vQESNS'].sYear=='y2045'].groupby(['sST','sES']).sum().vQESNS).sum()*pESNSCost*YrGap* (1/((1+DisRate)**(YrGap*(6-1))))\n", + "ESNSTotalCosts_2050=(d_vars['vQESNS'][d_vars['vQESNS'].sYear=='y2050'].groupby(['sST','sES']).sum().vQESNS).sum()*pESNSCost*YrGap* (1/((1+DisRate)**(YrGap*(7-1))))\n", + "\n", + "OpVaromCost_2020 = (d_vars['vOpVarom'][(d_vars['vOpVarom'].sYear=='y2020')].vOpVarom.sum())*(YrGap* (1/((1+DisRate)**(YrGap*(1-1)))))\n", + "OpVaromCost_2025 = (d_vars['vOpVarom'][(d_vars['vOpVarom'].sYear=='y2025')].vOpVarom.sum())*(YrGap* (1/((1+DisRate)**(YrGap*(2-1)))))\n", + "OpVaromCost_2030 = (d_vars['vOpVarom'][(d_vars['vOpVarom'].sYear=='y2030')].vOpVarom.sum())*(YrGap* (1/((1+DisRate)**(YrGap*(3-1)))))\n", + "OpVaromCost_2035 = (d_vars['vOpVarom'][(d_vars['vOpVarom'].sYear=='y2035')].vOpVarom.sum())*(YrGap* (1/((1+DisRate)**(YrGap*(4-1)))))\n", + "OpVaromCost_2040 = (d_vars['vOpVarom'][(d_vars['vOpVarom'].sYear=='y2040')].vOpVarom.sum())*(YrGap* (1/((1+DisRate)**(YrGap*(5-1)))))\n", + "OpVaromCost_2045 = (d_vars['vOpVarom'][(d_vars['vOpVarom'].sYear=='y2045')].vOpVarom.sum())*(YrGap* (1/((1+DisRate)**(YrGap*(6-1)))))\n", + "OpVaromCost_2050 = (d_vars['vOpVarom'][(d_vars['vOpVarom'].sYear=='y2050')].vOpVarom.sum())*(YrGap* (1/((1+DisRate)**(YrGap*(7-1)))))\n", + "\n", + "\n", + " \n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "OpCost = [y2020opcost, y2025opcost, y2030opcost, y2035opcost, y2040opcost,y2045opcost,y2050opcost]\n", + "TotalCost_vQPEtoCE = [1e-3*TotalCost_vQPEtoCE2020.sum(), 1e-3*TotalCost_vQPEtoCE2025.sum(), 1e-3*TotalCost_vQPEtoCE2030.sum(),1e-3* TotalCost_vQPEtoCE2035.sum(), 1e-3*TotalCost_vQPEtoCE2040.sum(), 1e-3*TotalCost_vQPEtoCE2045.sum(), 1e-3*TotalCost_vQPEtoCE2050.sum()]\n", + "TotalCEActive_FixomCost = [TotalCEActive_FixomCost2020.sum(), TotalCEActive_FixomCost2025.sum(), TotalCEActive_FixomCost2030.sum(),TotalCEActive_FixomCost2035.sum(), TotalCEActive_FixomCost2040.sum(), TotalCEActive_FixomCost2045.sum(), TotalCEActive_FixomCost2050.sum()]\n", + "TotalSTCap_Fixom = [1e-6*TotalSTCap_FixomCost2020.sum(), 1e-6*TotalSTCap_FixomCost2025.sum(), 1e-6*TotalSTCap_FixomCost2030.sum(),1e-6*TotalSTCap_FixomCost2035.sum(), 1e-6*TotalSTCap_FixomCost2040.sum(), 1e-6*TotalSTCap_FixomCost2045.sum(), 1e-6*TotalSTCap_FixomCost2050.sum()]\n", + "TotaSTVarom = [1e-6*TotalVaromSTCost_2020.sum(),1e-6* TotalVaromSTCost_2025.sum(), 1e-6*TotalVaromSTCost_2030.sum(),1e-6*TotalVaromSTCost_2035.sum(), 1e-6*TotalVaromSTCost_2040.sum(), 1e-6*TotalVaromSTCost_2045.sum(), 1e-6*TotalVaromSTCost_2050.sum()]\n", + "TotalESNSCost = [ESNSTotalCosts_2020, ESNSTotalCosts_2025, ESNSTotalCosts_2030,ESNSTotalCosts_2035, ESNSTotalCosts_2040, ESNSTotalCosts_2045, ESNSTotalCosts_2050]\n", + "TotalOpVaromCost = [1e-3*OpVaromCost_2020, 1e-3*OpVaromCost_2025, 1e-3*OpVaromCost_2030, 1e-3*OpVaromCost_2035, 1e-3*OpVaromCost_2040,1e-3* OpVaromCost_2045, 1e-3*OpVaromCost_2050]\n", + "\n", + "plt.figure(figsize=(10, 5))\n", + "plt.plot(years, OpCost, marker='o')\n", + "plt.plot(years, TotalCost_vQPEtoCE,TotalCEActive_FixomCost,marker='o')\n", + "plt.plot(years, TotalSTCap_Fixom,TotaSTVarom,marker='o')\n", + "plt.plot(years, TotalESNSCost,TotalOpVaromCost,marker='o')\n", + "plt.title('Operational Cost')\n", + "plt.legend(['Operational Cost', 'Total Cost vQPE to CE', 'Total CE Active Fixom Cost','Total ST Cap Fixom','Total ST Varom','Total ESNS Cost','Total Op Varom Cost'])\n", + "plt.xlabel('Year')\n", + "plt.ylabel('Operational Cost [MEuro]')\n", + "plt.grid()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import pandas as pd\n", + "pPECost = pd.DataFrame(list(data['pPECost'].items()),columns = ['sPE','pPECost'])\n", + "pPECost[['sPE', 'sYear']] = pd.DataFrame(pPECost['sPE'].tolist(), index=pPECost.index)\n", + "pPECost = pPECost.set_index('sPE')\n", + "\n", + "TotalCost_vQPEtoCE2020_Imported = (d_vars['vQPEImp'][(d_vars['vQPEImp'].sYear=='y2020')].groupby('sPE').sum().vQPEImp)*(pPECost[pPECost.sYear=='y2020'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(1-1)))))\n", + "TotalCost_vQPEtoCE2025_Imported = (d_vars['vQPEImp'][(d_vars['vQPEImp'].sYear=='y2025')].groupby('sPE').sum().vQPEImp)*(pPECost[pPECost.sYear=='y2025'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(2-1)))))\n", + "TotalCost_vQPEtoCE2030_Imported = (d_vars['vQPEImp'][(d_vars['vQPEImp'].sYear=='y2030')].groupby('sPE').sum().vQPEImp)*(pPECost[pPECost.sYear=='y2030'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(3-1)))))\n", + "TotalCost_vQPEtoCE2035_Imported = (d_vars['vQPEImp'][(d_vars['vQPEImp'].sYear=='y2035')].groupby('sPE').sum().vQPEImp)*(pPECost[pPECost.sYear=='y2035'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(4-1)))))\n", + "TotalCost_vQPEtoCE2040_Imported = (d_vars['vQPEImp'][(d_vars['vQPEImp'].sYear=='y2040')].groupby('sPE').sum().vQPEImp)*(pPECost[pPECost.sYear=='y2040'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(5-1)))))\n", + "TotalCost_vQPEtoCE2045_Imported = (d_vars['vQPEImp'][(d_vars['vQPEImp'].sYear=='y2045')].groupby('sPE').sum().vQPEImp)*(pPECost[pPECost.sYear=='y2045'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(6-1)))))\n", + "TotalCost_vQPEtoCE2050_Imported = (d_vars['vQPEImp'][(d_vars['vQPEImp'].sYear=='y2050')].groupby('sPE').sum().vQPEImp)*(pPECost[pPECost.sYear=='y2050'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(7-1)))))\n", + "\n", + "TotalCost_vQPEtoCE2020_Domestic = (d_vars['vQPEDom'][(d_vars['vQPEDom'].sYear=='y2020')].groupby('sPE').sum().vQPEDom)*(pPECost[pPECost.sYear=='y2020'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(1-1)))))\n", + "TotalCost_vQPEtoCE2025_Domestic = (d_vars['vQPEDom'][(d_vars['vQPEDom'].sYear=='y2025')].groupby('sPE').sum().vQPEDom)*(pPECost[pPECost.sYear=='y2025'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(2-1)))))\n", + "TotalCost_vQPEtoCE2030_Domestic = (d_vars['vQPEDom'][(d_vars['vQPEDom'].sYear=='y2030')].groupby('sPE').sum().vQPEDom)*(pPECost[pPECost.sYear=='y2030'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(3-1)))))\n", + "TotalCost_vQPEtoCE2035_Domestic = (d_vars['vQPEDom'][(d_vars['vQPEDom'].sYear=='y2035')].groupby('sPE').sum().vQPEDom)*(pPECost[pPECost.sYear=='y2035'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(4-1)))))\n", + "TotalCost_vQPEtoCE2040_Domestic = (d_vars['vQPEDom'][(d_vars['vQPEDom'].sYear=='y2040')].groupby('sPE').sum().vQPEDom)*(pPECost[pPECost.sYear=='y2040'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(5-1)))))\n", + "TotalCost_vQPEtoCE2045_Domestic = (d_vars['vQPEDom'][(d_vars['vQPEDom'].sYear=='y2045')].groupby('sPE').sum().vQPEDom)*(pPECost[pPECost.sYear=='y2045'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(6-1)))))\n", + "TotalCost_vQPEtoCE2050_Domestic = (d_vars['vQPEDom'][(d_vars['vQPEDom'].sYear=='y2050')].groupby('sPE').sum().vQPEDom)*(pPECost[pPECost.sYear=='y2050'].pPECost)*(YrGap* (1/((1+DisRate)**(YrGap*(7-1)))))\n", + "\n", + "# Now lets graph the operational costs of PE\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "TotalCost_vQPEtoCE_Imported = [1e-3*TotalCost_vQPEtoCE2020_Imported.sum(), 1e-3*TotalCost_vQPEtoCE2025_Imported.sum(), 1e-3*TotalCost_vQPEtoCE2030_Imported.sum(),1e-3* TotalCost_vQPEtoCE2035_Imported.sum(), 1e-3*TotalCost_vQPEtoCE2040_Imported.sum(), 1e-3*TotalCost_vQPEtoCE2045_Imported.sum(), 1e-3*TotalCost_vQPEtoCE2050_Imported.sum()]\n", + "TotalCost_vQPEtoCE_Domestic = [1e-3*TotalCost_vQPEtoCE2020_Domestic.sum(), 1e-3*TotalCost_vQPEtoCE2025_Domestic.sum(), 1e-3*TotalCost_vQPEtoCE2030_Domestic.sum(),1e-3* TotalCost_vQPEtoCE2035_Domestic.sum(), 1e-3*TotalCost_vQPEtoCE2040_Domestic.sum(), 1e-3*TotalCost_vQPEtoCE2045_Domestic.sum(), 1e-3*TotalCost_vQPEtoCE2050_Domestic.sum()]\n", + "TotalCost_vQPEtoCE = [1e-3*TotalCost_vQPEtoCE2020.sum(), 1e-3*TotalCost_vQPEtoCE2025.sum(), 1e-3*TotalCost_vQPEtoCE2030.sum(),1e-3* TotalCost_vQPEtoCE2035.sum(), 1e-3*TotalCost_vQPEtoCE2040.sum(), 1e-3*TotalCost_vQPEtoCE2045.sum(), 1e-3*TotalCost_vQPEtoCE2050.sum()]\n", + "\n", + "plt.figure(figsize=(10, 5))\n", + "plt.plot(years, TotalCost_vQPEtoCE_Imported, marker='o')\n", + "plt.plot(years, TotalCost_vQPEtoCE_Domestic, marker='o')\n", + "plt.plot(years, TotalCost_vQPEtoCE, 'ko-')\n", + "plt.title('Operational Cost of PE')\n", + "plt.legend(['Total Cost vQPE to CE Imported', 'Total Cost vQPE to CE Domestic', 'Total Cost vQPE to CE'])\n", + "plt.xlabel('Year')\n", + "plt.ylabel('Operational Cost [MEuro]')\n", + "plt.grid()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA2wAAAHWCAYAAAALogprAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAACxW0lEQVR4nOzdd3xO9///8ceVvROxIqQSxFaK1gixxZ7VGv0YVasUNYpWiajasxRddJitUTVCalOrdtUqUtRqrYggkZzfH365vq4mSDRxXXjeb7frdnOd8z7nPM95R5JX3ud6H5NhGAYiIiIiIiJic+ysHUBERERERERSp4JNRERERETERqlgExERERERsVEq2ERERERERGyUCjYREREREREbpYJNRERERETERqlgExERERERsVEq2ERERERERGyUCjYREREREREbpYJNRESeC9HR0ZhMJmbPnm3tKABUrVqVqlWrWjuGVXz77bcULlwYR0dHfHx8rB1HRMSmqWATERGzQ4cO8cYbb5A7d26cnZ3x9/enTZs2HDp0yNrR0mzu3LlMmjTJ2jEyVGJiIrNmzaJq1ar4+vri7OxMYGAgHTp04Ndff82UY65cuZLw8PAM3++RI0do3749+fPn5/PPP+ezzz57YNvw8HBMJpP55ebmRtGiRRk8eDAxMTHmdrNnz7Zo9+/X9u3bM/w8RESeFAdrBxAREduwePFiWrVqha+vLx07diQoKIjo6Gi+/PJLfvjhB+bPn0/Tpk2tHfOR5s6dy2+//Ubv3r0tlufNm5dbt27h6OhonWCP6datWzRr1ozIyEhCQ0N5//338fX1JTo6moULF/L1119z+vRp8uTJk6HHXblyJdOmTcvwom3Dhg0kJSUxefJkChQokKZtpk+fjoeHB7GxsaxZs4YRI0awbt06tm7dislkMreLiIggKCgoxfZpPY6IiC1SwSYiIpw4cYL//e9/5MuXj02bNpE9e3bzul69elG5cmX+97//ceDAAfLly/dEs8XFxeHm5vaf92MymXBxccmARE9W//79iYyMZOLEiSmK0KFDhzJx4kTrBHtMly5dAkjXrZCvvvoq2bJlA6Br1640b96cxYsXs337dipUqGBuV7duXcqWLZuheUVErE23RIqICGPHjiUuLo7PPvvMolgDyJYtGzNnzuTmzZuMGTPGvDz5drUjR47w2muv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2Jr+/fszevRoFixYwNGjRxk4cCD79u2jV69eAOTIkQNXV1ciIyO5ePEi16/f+8x2cHAw3377LYcPH2bHjh20adPGPLFGWk2bNo3ExEReeeUVFi1axPHjxzl8+DBTpkyhQoUKANSsWZMSJUrQpk0b9uzZw86dO+nWrRtVqlShbNmy3Lp1ix49erBhwwb+/PNPtm7dyq5duyhSpAhw79llsbGxrF27ln/++eehE7U0a9aMGzdu0K1bN6pVq4a/v795XYUKFejVqxf9+/dn/PjxnDhxgiNHjjB48GCmTJnC559/TtasWdN1/jdu3ODChQsWr5iYmAe2DwwMZNOmTfz111/m4rhv376sXbuW4cOHc+zYMb7++mumTp2a6uQqyXr37k1ISAg1atRg2rRp7N+/n5MnT7Jw4ULKly9vnnAG4M6dOykypqcwl4yhgk1sUrMijkT38iCqvQ99+vQhqr0Pp3u7UyirHWdiDOp8F8fVW2m/B1tERMRWNGvWjOjoaNavX8/cuXNZv349p06dssozRnv27EmfPn3o27cvJUqUIDIykmXLlpkn7nBwcGDKlCnMnDkTf39/GjduDMCXX37J1atXKV26NP/73//o2bMnOXLkSNex8+XLx549e6hWrRp9+/alePHi1KpVi7Vr1zJ9+nTg3sjjjz/+SJYsWQgNDaV27doEBgYyb9484N6o5eXLl2nbti0FCxbktddeo27dugwbNgyAihUr0rVrV15//XWyZ8/OmDFjHpjH09OThg0bsn//ftq0aZNi/aRJk/j000+ZN28exYsXp0iRIowdO5Z169bxxhtvpOvcAYYMGUKuXLksXu+9994D20dERBAdHU3+/PnNk8GULl2ahQsXMn/+fIoXL86QIUOIiIh44IQjcO85alFRUbz33nvMnDmT8uXL8/LLLzNlyhR69uxJ8eLFzW0jIyNTZKxUqVK6z1X+G5ORnk8eyn8SExODt7c3169fx8vLy9pxbHKWyH9LsHNhZcnPqLe/M45Jt/nzWhIVv7rJuRsGlV6wZ80bbrg62sDtkc/hLJEJCQmsXLmSevXq4ehoQzN2CqD+sWXqG9v2sP65ffs2p06dIigoCBcXFyslfL4lJSURExODl5cXdnbWHXeIjo6mSpUqVKhQgTlz5tj85w4zmy31jS152PeNtNYGupryVMnrY0dkGze8nWHL6URa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S5fy9ttvYxiGtWOJiIiIiBWoYBOxQaGhocybNw87Ozs+//xzwsPDrR1JRERERKxABZuIjWratCmffvopABEREcyYMcPKiURERETkSVPBJmLDunTpwtChQwF4++23WbRokZUTiYiIiMiTpIJNxMYNHTqUzp07YxgGrVu3ZuPGjdaOJCIiIiJPiAo2ERtnMpn49NNPadq0KfHx8TRq1IgDBw5YO5aIiIiIPAEq2ESeAvb29sydO5fKlSsTExNDnTp1iI6OtnYsEREREclkKthEnhIuLi4sW7aM4sWLc/78ecLCwvjnn3+sHUtEREREMpEKNpGniI+PD5GRkbzwwgscO3aM+vXrc/PmTWvHEhEREZFMooJN5CmTO3duVq9eja+vLzt37qRFixYkJCRYO5aIiIiIZAIVbCJPocKFC7NixQpcXV1ZtWoVb731FoZhWDuWiIiIiGQwFWwiT6ny5cvz/fffY29vzzfffMPAgQOtHUlEREREMpgKNpGnWP369fniiy8AGDNmDJMmTbJuIBERERHJUCrYRJ5y7du3Z+TIkQC8++67zJs3z8qJRERERCSjqGATeQYMGDCAXr16AdCuXTuioqKsnEhEREREMoIKNpFngMlkYsKECbRs2ZKEhASaNWvG7t27rR1LRERERP4jFWwizwg7Oztmz55NjRo1iI2NpW7duvzxxx/WjiUiIiIi/4EKNpFniLOzM4sXL+all17i77//JiwsjAsXLlg7loiIiIg8JhVsIs8YLy8vVq1aRb58+Th58iR169YlJibG2rFERERE5DE4pKVRs2bN0r3jGTNmkCNHjnRvJyL/Xc6cOVm9ejUhISHs27ePpk2bsnLlSpydna0dTURERETSIU0jbEuXLsXJyQlvb+80vVasWEFsbGxmZxeRhyhQoACrVq3Cw8ODdevW0bZtW5KSkqwdS0RERETSIU0jbABTpkxJ84jZDz/88NiBRCTjlC5dmiVLllCvXj0WLlyIn58fkyZNwmQyWTuaiIiIiKRBmkbY1q9fj6+vb5p3umrVKnLnzv3YoUQk49SsWZNvvvkGuPeHl9GjR1s5kYiIiIikVZoKtipVquDgkObBOCpVqqTPyojYkJYtWzJp0iQABg0axKxZs6wbSERERETSJO1V2H0SExNZunQphw8fBqBYsWI0atQIe3v7DA0nIhmnV69enD9/ntGj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oHnz5no+WiIiqi0MbERERFqQn5+Pjh074tatW1i3bh1OnDiBffv2YceOHeoxWVlZcHR0RGZmJtq3b19uHzdu3EDTpk2Rnp6OTp06qQPbd999h4kTJ9bm4RARkYHgkkgiIiItaNasGcaPHw83NzcMGTIEqamp2L17Nxo1aqR+uLq6AoB62ePZs2cxcuRIvPTSS7CwsICTkxMA4MqVKxr79vX1rdVjISIiwyHTdwFERET1hUwmg0xW+qv13r17GDhwIGbPnl1uXNmSxoEDB6J169ZYtGgRWrRoAZVKhU6dOqGkpERjvLm5ue6LJyIig8TARkREpAPe3t5Yt24dnJyc1CHuaTdv3kRmZiYWLVqEXr16AQD2799f22USEZGB45JIIiIiHQgLC8OtW7cwcuRIHD16FOfPn8eOHTswduxYKJVKWFtbo0mTJvj5559x7tw5xMfHIzIyUt9lExGRgWFgIyIi0oEWLVrgwIEDUCqV6NevH9zd3REREQErKytIJBJIJBKsXLkSycnJ6NSpEz755BPMmTNH32UTEZGB4V0iiYiIiIiIDBTPsBERERERERkoBjYiIiIiIiIDxcBGRERERERkoBjYiIiIiIiIDBQDGxERERERkYFiYCMiIiIiIjJQDGxEREREREQGioGNiIiIiIjIQDGwERERERERGSgGNiIiIiIiIgPFwEZERERERGSg/j/Hh+ANyn5LRQAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Use the same data as before but now we will plot the results in a stacked bar plot without the variable TotalCost_vQPEtoCE as a normal plot with a mark o and black color\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "\n", + "plt.figure(figsize=(10, 5))\n", + "plt.plot(years, TotalCost_vQPEtoCE, 'ko-')\n", + "plt.bar(years, TotalCost_vQPEtoCE_Domestic)\n", + "plt.bar(years, TotalCost_vQPEtoCE_Imported, bottom=TotalCost_vQPEtoCE_Domestic)\n", + "plt.title('Operational Cost of PE')\n", + "plt.legend(['Total Cost vQPE to CE','Total Cost vQPE to CE Domestic', 'Total Cost vQPE to CE Imported'])\n", + "plt.xlabel('Year')\n", + "plt.ylabel('Operational Cost [MEuro]')\n", + "plt.grid()" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1IAAAHWCAYAAAB9mLjgAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAAA7YUlEQVR4nO3de5iN9f7/8deaMeaAGcZhDoxmlPMhlWikIsNspU20kQ622qmQmAulnWP6irZDidCBDqZoi12qYYxDW+RU2kjCNjuFUTTGcSwz9++PLuvXag7Wh7Vm3TPzfFyXS/fn/qx7ve/1ntv0uu7DcliWZQkAAAAA4LEAfxcAAAAAAKUNQQoAAAAADBGkAAAAAMAQQQoAAAAADBGkAAAAAMAQQQoAAAAADBGkAAAAAMAQQQoAAAAADBGkAAAAAMAQQQoAAAAADBGkAABet2DBAjkcDm3dutUv75+Xl6f58+erffv2ioyMVHBwsOLj49W/f3+f1fTpp59q3Lhxxq9bunSpunTpoho1aqhixYqKjY1Vr169tHr1atectWvXyuFwFPnn/fff9+KeAAA8UcHfBQAA4E1nz55Vjx49lJaWpltvvVXPPPOMIiMjlZmZqcWLF+utt97SDz/8oDp16nj1fT/99FPNmjXL4zBlWZYeeughLViwQNddd51SUlIUHR2tw4cPa+nSperYsaO++OILtW3b1vWaIUOG6MYbbyywrcTERG/tBgDAQwQpAECZMmLECKWlpWn69OkaOnSo27qxY8dq+vTp/insD6ZOnaoFCxZo6NChmjZtmhwOh2vd3//+d73zzjuqUMH91/Qtt9yie+65p6RLBQAUgkv7AAAl4q9//asqV66sn376Sd27d1flypVVs2ZNDR8+XHl5eZIkp9OpyMhI9e/fv8Drc3JyFBISouHDhxf5Hj/++KPmzp2rTp06FQhRkhQYGKjhw4e7nY36+uuv1aVLF4WHh6ty5crq2LGjvvzyS7fXOZ1OjR8/XvXr11dISIiqV6+udu3aKT093bVvs2bNkiS3S+6KcvbsWU2aNEmNGjXSP/7xj0LnPvDAA2rdunWR2wAA+BdnpAAAJSYvL0/Jyclq06aN/vGPf2jVqlWaOnWqrr76aj3++OMKCgrS3XffrQ8//FBz585VxYoVXa9dtmyZcnNz1adPnyK3/9lnn+nChQt64IEHPKpn165duuWWWxQeHq6RI0cqKChIc+fOVfv27bVu3Tq1adNGkjRu3DhNmjRJf/vb39S6dWvl5ORo69at+uqrr9SpUyc9+uijOnTokNLT0/XOO+9c8n3Xr1+v48ePa+jQoQoMDPSoVkk6efKkfvnllwLj1atXLza4AQC8jyAFACgx586dU+/evTV69GhJ0mOPPabrr79eb7zxhh5//HFJUu/evfXmm29q5cqV6tq1q+u1ixYtUr169dSqVasit797925JUvPmzT2q59lnn5XT6dT69etVr149SdKDDz6ohg0bauTIkVq3bp0k6ZNPPtEdd9yhefPmFbqdxMRENWjQQOnp6br//vsv+b6mdV700EMPFTp++PBhRUdHG20LAHBlCFIAgBL12GOPuS3fcsstbmdxbr/9dtWoUUOLFi1yBalff/1V6enpxV7WJ/12+Z8kValS5ZJ15OXlaeXKlerevbsrRElSTEyM+vbtq9dee005OTkKDw9X1apVtWvXLu3du1f169f3eF+9UefvjRkzRrfcckuB8cjIyCuuCQBghiAFACgxISEhqlmzpttYtWrV9Ouvv7qWK1SooJ49eyo1NVW5ubkKDg7Whx9+KKfTqd69exe7/fDwcEm/XQJ3KT///LPOnDmjhg0bFljXuHFj5efn6+DBg2ratKkmTJigbt26qUGDBmrWrJn+9Kc/6YEHHlCLFi082e0rqvP3mjdvrqSkpMt6TwCAd/GwCQBAifH0fqA+ffro5MmT+uyzzyRJixcvVqNGjXTttdcW+7pGjRpJknbs2HFlhf7Brbfeqv379+vNN99Us2bN9Prrr+v666/X66+/flnb81WdAICSQ5ACANjOrbfeqpiYGC1atEi//PKLVq9efcmzUZLUpUsXBQYG6t13373k3Jo1ayosLEx79uwpsO67775TQECA4uLiXGMXnyb43nvv6eDBg2rRooXbd0aZPOyhXbt2qlatmt577z3XEwsBAKULQQoAYDsBAQG655579PHHH+udd97RhQsXPApScXFxeuSRR7Ry5UrNnDmzwPr8/HxNnTpVP/74owIDA9W5c2f961//UmZmpmtOVlaWUlNT1a5dO9cleMeOHXPbTuXKlXXNNdcoNzfXNVapUiVJUnZ29iXrDAsL01NPPaXdu3frqaeekmVZBea8++672rx58yW3BQDwD+6RAgDYUu/e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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# InvCostCE\n", + "y2020invCE=d_vars['vInvCostCE'][(d_vars['vInvCostCE'].sYear=='y2020')].vInvCostCE.sum()\n", + "y2025invCE=d_vars['vInvCostCE'][(d_vars['vInvCostCE'].sYear=='y2025')].vInvCostCE.sum()\n", + "y2030invCE=d_vars['vInvCostCE'][(d_vars['vInvCostCE'].sYear=='y2030')].vInvCostCE.sum()\n", + "y2035invCE=d_vars['vInvCostCE'][(d_vars['vInvCostCE'].sYear=='y2035')].vInvCostCE.sum()\n", + "y2040invCE=d_vars['vInvCostCE'][(d_vars['vInvCostCE'].sYear=='y2040')].vInvCostCE.sum()\n", + "y2045invCE=d_vars['vInvCostCE'][(d_vars['vInvCostCE'].sYear=='y2045')].vInvCostCE.sum()\n", + "y2050invCE=d_vars['vInvCostCE'][(d_vars['vInvCostCE'].sYear=='y2050')].vInvCostCE.sum()\n", + "\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "values = [y2020invCE, y2025invCE, y2030invCE, y2035invCE, y2040invCE, y2045invCE, y2050invCE]\n", + "\n", + "plt.figure(figsize=(10, 5))\n", + "plt.bar(years, values)\n", + "plt.title('Inv Cost CE')\n", + "plt.xlabel('Year')\n", + "plt.ylabel('Inv Cost CE [GEuro]')\n", + "plt.grid()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1IAAAHWCAYAAAB9mLjgAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAAA7U0lEQVR4nO3de5iN9f7/8deagxljLAyZIeO0K4ec2ZhUzjN7Uo57k1J2285OIzHfsP12GNRVaRcl0sGhA5FdSpIxhpSQQ7GdksRGzCiaGcdlmXX//uiyLqsxrA9rZt3D83Fdc3Hfn8+61/teb/fMvNz3upfDsixLAAAAAAC/hQS7AAAAAAAoaQhSAAAAAGCIIAUAAAAAhghSAAAAAGCIIAUAAAAAhghSAAAAAGCIIAUAAAAAhghSAAAAAGCIIAUAAAAAhghSAAAAAGCIIAUACLjZs2fL4XBo48aNQXn+/Px8zZo1S+3atVNMTIwiIiJUs2ZNPfTQQ0VW05IlS5SWlub3fI/Ho7ffflutWrVSTEyMypYtq1tuuUUPPvig1q1bJ0mqWbOmHA7HZb9mz55dJPsEAChcWLALAAAgkE6fPq2ePXtq6dKluvPOO/X//t//U0xMjPbt26f3339fb731lvbv369q1aoF9HmXLFmiqVOn+h2mhgwZoqlTp6pbt266//77FRYWpl27dumzzz5T7dq11bp1a02ePFknTpzweY733ntPkyZNUqVKlbzrb7vttoDuCwDg8ghSAIBryvDhw7V06VJNmjRJQ4cO9RkbO3asJk2aFJzCLpCdna1p06bp4Ycf1uuvv+4zNnnyZP3888+SpO7du/uMZWVl6b333lP37t1Vs2bNYqoWAHAxXNoHACgWf/3rXxUdHa2ffvpJ3bt3V3R0tG644QY98cQTys/PlyS53W7FxMTooYceKvD4vLw8RUZG6oknnij0OQ4ePKjXXntNnTt3LhCiJCk0NFRPPPGEz9mob7/9VsnJyXI6nYqOjlbHjh29l9ad53a7NW7cON18882KjIxUxYoVdfvttysjI8O7b1OnTpUkn0vuCrN3715ZlqU2bdoUGHM4HKpcuXKhjwUA2ANBCgBQbPLz85WUlKSKFSvq3//+t9q2basXXnjBe1YmPDxcPXr00EcffaSzZ8/6PPajjz6Sy+XSvffeW+j2P/vsM507d04PPPCAX/Vs375dd9xxh7Zs2aIRI0Zo9OjR2rt3r9q1a6evv/7aOy8tLU3jxo1T+/bt9corr+hf//qXqlevrm+++UaS9I9//EOdO3eWJL3zzjver8LUqFFDkrRgwQKdOnXKr1oBAPbCpX0AgGJz5swZ9enTR6NHj5YkPfLII2rWrJlmzJihQYMGSZL69OmjmTNnatmyZbr77ru9j50/f75q166tFi1aFLr9nTt3SpIaNmzoVz1PPvmk3G63Vq9erdq1a0uSHnzwQdWpU0cjRozQqlWrJEmffvqp7rrrrgKX4Z2XkJCgW265RRkZGerXr99ln7dKlSp68MEH9fbbb6tatWpq166d2rRpoy5duqhu3bp+1Q4ACC7OSAEAitUjjzzis3zHHXfoxx9/9C536NBBlSpV0vz5873rfv31V2VkZKhPnz6X3HZeXp4kqWzZspetIz8/X8uWLVP37t29IUr6LeTcd999Wr16tXd75cuX1/bt27V79+7L76CfZs2apVdeeUW1atXSwoUL9cQTT6hevXrq2LGjfvrpp4A9DwCgaBCkAADFJjIyUjfccIPPugoVKujXX3/1LoeFhalXr176+OOP5XK5JEkffvih3G73ZYOU0+mUJB0/fvyytfz88886deqU6tSpU2CsXr168ng8OnDggCRp/PjxysnJ0S233KKGDRtq+PDh+u9//3vZ57iUkJAQpaSkaNOmTfrll1/08ccfKzk5WStWrLjk5YsAAHsgSAEAik1oaKhf8+69914dP35cn332mSTp/fffV926ddW4ceNLPu78ZXFbt269ukJ/584779SePXs0c+ZMNWjQQG+++aaaNWumN998MyDbr1ixorp27aolS5aobdu2Wr16tf73v/8FZNsAgKJBkAIA2M6dd96pKlWqaP78+frll1+0YsWKy56NkqTk5GSFhobq3XffvezcG264QVFRUdq1a1eBse+++04hISGKj4/3rjt/N8H33ntPBw4cUKNGjXw+M+pSd+kzcf49YIcPHw7I9gAARYMgBQCwnZCQEP35z3/WJ598onfeeUfnzp3zK0jFx8fr4Ycf1rJlyzRlypQC4x6PRy+88IIOHjyo0NBQJSYm6uOPP9a+ffu8c7KzszV37lzdfvvt3ksFjx496rOd6Oho3XTTTd5LDyWpTJkykqScnJzL1pmVlaUdO3YUWH/27FllZmYqJCRE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1/Lly9WoUSOFh4f7jL/44osBKw4AAAAA7Mg4SP33v/9VkyZNJEnbtm3zGePGEwAAAACuB8ZBauXKlUVRBwAAAACUGMbvkQIAAACA653fZ6R69uzp17wPP/zwiosBAAAAgJLA7yBVrly5oqwDAAAAAEoMv4PUrFmzirIOAAAAACgxeI8UAAAAABgiSAEAAACAIYIUAAAAABgiSAEAAACAIYIUAAAAABgiSAEAAACAIYIUAAAAABgiSAEAAACAIYIUAAAAABgiSAEAAACAIYIUAAAAABgiSAEAAACAIYIUAAAAABgiSAEAAACAIYIUAAAAABgiSAEAAACAIYIUAAAAABgiSAEAAACAIYIUAAAAABgiSAEAAACAIYIUAAAAABgiSAEAAACAIYIUAAAAABgiSAEAAACAIYIUAAAAABgiSAEAAACAIYIUAAAAABgiSAEAAACAIYIUAAAAABgiSAEAAACAIYIUAAAAABgiSAEAAACAIYIUAAAAABgiSAEAAACAIYIUAAAAABgiSAEAAACAIYIUAAAAABgiSAEAAACAIYIUAAAAABgiSAEAAACAIYIUAAAAABgiSAEAAACAoaAGqS+++EL33HOPqlatKofDoY8++shn3LIsjRkzRlWqVFHp0qXVqVMn7d6922fOsWPHdP/998vpdKp8+fIaMGCATpw4UYx7AQAAAOB6E9QgdfLkSTVu3FhTp0696PjEiRP18ssva/r06fr6669VpkwZJSUl6cyZM945999/v7Zv366MjAwtXrxYX3zxhQYOHFhcuwAAAADgOhQWzCdPTk5WcnLyRccsy9LkyZP15JNPqlu3bpKkt99+W7Gxsfroo4907733aufOnVq6dKk2bNigFi1aSJKmTJmiu+66S//+979VtWrVi27b5XLJ5XJ5l/Py8iRJbrdbbrc7kLt4RSJCrWCXcEkRIZbPn3YW6H7avTdSyelPURxr9Cdwrsf+lJTeSIHvT4O09IBuryhEhFia0EJqPn6pXB5HsMsp1La0pGCXUOzO/3u0w+9QKIj+mPP3tXJYlmWLnxgOh0MLFy5U9+7dJUk//vij/vCHP+jbb79VkyZNvPPatm2rJk2a6KWXXtLMmTP1f//3f/r111+94+fOnVNkZKQWLFigHj16XPS50tLSNG7cuALr586dq6ioqIDuFwAAAICS49SpU7rvvvuUm5sr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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# InvCostST\n", + "# Now lets graph the investment costs for supply technologies\n", + "y2020invST = d_vars['vInvCostST'][(d_vars['vInvCostST'].sYear=='y2020')].vInvCostST.sum()\n", + "y2025invST = d_vars['vInvCostST'][(d_vars['vInvCostST'].sYear=='y2025')].vInvCostST.sum()\n", + "y2030invST = d_vars['vInvCostST'][(d_vars['vInvCostST'].sYear=='y2030')].vInvCostST.sum()\n", + "y2035invST = d_vars['vInvCostST'][(d_vars['vInvCostST'].sYear=='y2035')].vInvCostST.sum()\n", + "y2040invST = d_vars['vInvCostST'][(d_vars['vInvCostST'].sYear=='y2040')].vInvCostST.sum()\n", + "y2045invST = d_vars['vInvCostST'][(d_vars['vInvCostST'].sYear=='y2045')].vInvCostST.sum()\n", + "y2050invST = d_vars['vInvCostST'][(d_vars['vInvCostST'].sYear=='y2050')].vInvCostST.sum()\n", + "\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "values = [y2020invST, y2025invST, y2030invST, y2035invST, y2040invST, y2045invST, y2050invST]\n", + "\n", + "plt.figure(figsize=(10, 5))\n", + "plt.bar(years, values)\n", + "plt.title('Inv Cost ST')\n", + "plt.xlabel('Year')\n", + "plt.ylabel('Inv Cost ST [GEuro]')\n", + "plt.grid()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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Sp/3Tyru+XzixAnh5eUljI2NRdWqVcX06dNFSEiIounPn3bMv/76S3Tv3l3Y2toKIyMj4erqKnr16iX27t0rlZH7flLwPDh8+LDsuIhIN6mE0OHRrEREhOrVq8PDwwPbtm0r71CeaeHChQgODsalS5eKnXFNW5o0aQIbGxvs3bu3zI5BjzRu3BhVqlRBZGRkkX3BwcEICQlBcnIyTE1NyyE6IqLywzFSRESkFUIIhISEwMvLq0yTqCNHjuDYsWP46KOPyuwYr6Lc3Fzk5eVpbIuJicHx48fh7e1dpHxWVhbWrl0Lf39/JlFE9EriGCkiInoumZmZ2LJlC6Kjo/H3339j8+bNZXKckydPIiEhAd9++y0cHR3x/vvvl8lxXlXXrl2Dr68vPvzwQzg5OeHs2bNYsWIFHBwcNBYXvnnzJvbs2YNff/0V//33H0aOHFmOURMRlR8mUkRE9Fxu3bqFDz74ANbW1vjiiy/w7rvvlslxfv31V0ybNg1169bFTz/9BGNj4zI5zquqUqVKaNasGVauXIlbt27BzMwMXbp0wddff60xYcLp06fRt29f2NnZYdGiRSWur0RE9LLjGCkiIiIiIiKFOEaKiIiIiIhIISZSRERERERECnGMFID8/Hxcv34dFhYWUKlU5R0OERERERGVEyEE7t27BycnJ6jVJbc7MZECcP36dTg7O5d3GEREREREpCOuXr2KatWqlbifiRQACwsLAI8ulqWlZTlHQ0RERERE5SU9PR3Ozs5SjlASJlKA1J3P0tKSiRQRERERET1zyA8nmyAiIiIiIlKIiRQREREREZFCTKSIiIiIiIgU4hgpIiIiIqIK4OHDh8jNzS3vMCo8PT096OvrP/eyR0ykiIiIiIh0XEZGBv79918IIco7lJeCqakpHB0dYWhoWOo6mEgREREREemwhw8f4t9//4WpqSmqVKny3C0przIhBHJycnDr1i0kJSWhdu3aT11092mYSBERERER6bDc3FwIIVClShWYmJiUdzgVnomJCQwMDHD58mXk5OTA2Ni4VPVwsgkiIiIiogqALVHaU9pWKI06tBAHERERERHRK4WJFBERERERkUIcI0VEREREVAG96J5+nDBQE1ukiIiIiIhI62bNmoUWLVrAwsICdnZ26NatGxITEzXKZGVlISAgALa2tjA3N4e/vz9SUlKk/cePH0ef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iIiIiIgUYiJFRERERESkEBMpIiIiIiIihZhIERERERERKcREioiIiIiISCEuyEtERJLCazURERFRydgiRUREREREpBBbpIiIiIiIKqCYGNULPZ63t3ihx9N1bJEiIiIiIiKtmzVrFlq0aAELCwvY2dmhW7duSExM1CiTlZWFgIAA2NrawtzcHP7+/khJSZH2//fff+jUqROcnJxgZGQEZ2dnBAYGIj09XSoTExMDlUpV5JacnFym58dEioiIiIiItC42NhYBAQGIj49HZGQkcnNz0bFjR2RmZkplgoODsXXrVkRERCA2NhbXr19H9+7dpf1qtRpdu3bFli1bcO7cOYSFhWHPnj0YOnRokeMlJibixo0b0s3Ozq5Mz49d+4iISGepYmKk/0eXXxhERFQKO3fu1LgfFhYGOzs7JCQkoF27dkhLS0NISAjCw8PRvn17AEBoaCjc3d0RHx+P1q1bo1KlShg2bJhUh6urK4YPH465c+cWOZ6dnR2sra3L9JwKY4sUERERERGVubS0NACAjY0NACAhIQG5ubnw9fWVytSrVw8uLi6Ii4srto7r16/jt99+g5eXV5F9jRs3hqOjI9588038+eefZXAGmphIERERERFRmcrPz0dQUBDatGkDDw8PAEBycjIMDQ2LtCLZ29sXGd/Up08fmJqaomrVqrC0tMTKlSulfY6OjlixYgU2bNiADRs2wNnZGd7e3jh69GiZnhMTKSIiIiIiKlMBAQE4efIkfv7551I9fv78+Th69Cg2b96MixcvYtSoUdK+unXr4tNPP0WzZs3w+uuvY9WqVXj99dcxf/58bYVfLI6RIiIiIiKiMhMYGIht27Zh3759qFatmrTdwcEBOTk5SE1N1WiVSklJgYODg0YdDg4OcHBwQL169WBjY4O2bdti4sSJcHR0LPaYLVu2xP79+8vkfAqwRYqIiIiIiLROCIHAwEBs3LgRUVFRcHNz09jfrFkzGBgYYO/evdK2xMREXLlyBZ6eniXWm5+fDwDIzs4uscyxY8dKTLK0hS1SRERERESkdQEBAQgPD8fmzZthYWEhjXuysrKCiYkJrKysMHjwYIwaNQo2NjawtLTEiBEj4OnpidatWwMAfv/9d6SkpKBFixYwNzfHqVOnMGbMGLRp0wbVq1cHACxYsABubm5o0KABsrKysHLlSkRFRWH37t1len5M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REREREQvE9mJ1JQpUwAA2dnZ+PPPPxEbG4uYmBisWbMGubm5qFOnDtq3b19iNklERERERPSyULwgr5GREdq3b4+pU6ciNjYWN27cwPjx43H9+nWsWLGiLGIkIiIiIiLSKbJbpArk5OQgLi4OMTExiImJwcGDB1G1alX06NEDXl5eZREjERERERGRTpGdSE2bNk1KnFxdXdGuXTsMGTIE69at41TnRERERET0SlE0RsrFxQXffvstevbsCVtb27KMi4iIiIiICtH1Wfoqkvz8/OeuQ3YitWPHDkRHRyMsLAwjR45EnTp14O3tDS8vL3h5eaFKlSrPHQwREREREWkyMDCASqXCrVu3UKVKFahUqvIOqcISQiAnJwe3bt2CWq2GoaFhqeuSnUj5+flJi1rdu3cPf/zxB2JjYzFnzhz07dsXtWrVgo+PD5YsWVLqYIiIiIiISJOenh6qVauGf//9F5cuXSrvcF4KpqamcHFxgVqteO49ieLJJgDAwsICb731Fvz8/HDo0CFs2bIFy5Ytw/Lly5lIERERERFpmbm5OWrXro3c3NzyDqXC09PTg76+/nO37ClKpPLz83HkyBFER0cjJiYGf/75JzIzM1GtWjW899578PHxea5giIiIiIioeHp6etDT0yvvMOj/yU6kOnfujAMHDuDevXtwcnKCj48P5s+fDx8fH9SoUaMsYyQiIiIiItIpshMpa2trzJ07Fz4+Pqhdu3ZZxkRERERERKTTZCdSP/30U1nGQUREREREVGHITqSysrKwZ88evP322wCA8ePHIzs7W9qvp6eH6dOnw9jYWPtREhERERER6RDZiVRYWBi2b98uJVJLlixBgwYNYGJiAgA4e/YsnJycEBwcXDaREhERERER6QjZE6evW7cOQ4YM0dgWHh6O6OhoREdHY+7cuVi/fr3WAyQiIiIiItI1shOpCxcuoGHDhtJ9Y2NjjQWsWrZsidOnT2s3OiIiIiIiIh0ku2tfamqqxpioW7duaezPz8/X2E9ERERERPSykt0iVa1aNZw8ebLE/SdOnEC1atW0EhQREREREZEuk51IvfXWW5g0aRKysrKK7Hvw4AGmTp2KLl26aDU4IiIiIiIiXSS7a98XX3yB9evXo27duggMDESdOnUAAImJiViyZAny8vLwxRdflFmgREREREREukJ2ImVvb48DBw5g2LBhGDduHIQQAACVSoU333wTy5Ytg729fZkFSkREREREpCtkJ1IA4Obmhp07d+LOnTu4cOECAKBWrVqwsbEpk+CIiIiIiIh0kaJEqoCNjQ1atmyp7ViIiIiIiIgqBFmTTXTv3h3p6emyK+3bty9u3rxZ6qCIiIiIiIh0mawWqc2bNxdZN6okQghs3boV06dPh52d3XMFR0REREREpItkJVJCCGmWPiIiIiIioledrEQqOjpaccVVq1ZV/BgiIiIiIqKKQFYi5eXlVdZxEBERERERVRiyJpsgIiIiIiKix5hIERERERERKcREioiIiIiISCEmUkRERERERAopTqQmT56My5cvl0UsREREREREFYLiRGrz5s2oWbMmOnTogPDwcGRnZ5dFXERERERERDpLcSJ17NgxHD58GA0aNMDIkSPh4OCAYcOG4fDhw1oP7uHDh5g4cSLc3NxgYmKCmjVrYvr06RBCSGWEEJg0aRIcHR1hYmICX19fnD9/XuuxEBG9TGJiVNKNiIiIlCvVGKkmTZpg0aJFuH79OkJCQvDvv/+iTZs2aNSoERYuXIi0tDStBDd79mwsX74cS5YswZkzZzB79mzMmTMHixcvlsrMmTMHixYtwooVK3Dw4EGYmZnBz88PWVlZWomBiIiIiIjoSc812YQQArm5ucjJyYEQApUqVcKSJUvg7OyMX3755bmDO3DgALp27YouXbqgevXq6NGjBzp27IhDhw5Jx1+wYAG+/PJLdO3aFY0aNcLq1atx/fp1bNq06bmPT0REREREVJxSJVIJCQkIDAyEo6MjgoOD0aRJE5w5cwaxsbE4f/48ZsyYgc8+++y5g3v99dexd+9enDt3DgBw/Phx7N+/H507dwYAJCUlITk5Gb6+vtJjrKys0KpVK8TFxZVYb3Z2NtLT0zVuREREREREcukrfUDDhg1x9uxZdOzYESEhIXjnnXegp6enUaZPnz4YOXLkcwc3btw4pKeno169etDT08PDhw8xY8YM9O3bFwCQnJwMALC3t9d4nL29vbSvOLNmzcLUqVOfOz4iIiIiIno1KU6kevXqhUGDBqFq1aollqlcuTLy8/OfKzAAWL9+PdatW4fw8HA0aNAAx44dQ1BQEJycnNC/f/9S1zt+/HiMGjVKup+eng5nZ+fnjpeIiIiIiF4Nirv2FYyFetKDBw8wbdo0rQRVYMyYMRg3bhx69+6Nhg0bol+/fggODsasWbMAAA4ODgCAlJQUjcelpKRI+4pjZGQES0tLjRsREREREZFcihOpqVOnIiMjo8j2+/fva7273P3796FWa4aop6cntXa5ubnBwcEBe/fulfanp6fj4MGD8PT01GosREREREREBRR37RNCQKUquu7I8ePHYWNjo5WgCrzzzjuYMWMGXFxc0KBBA/z111+YN28eBg0aBABQqVQICgrCV199hdq1a8PNzQ0TJ06Ek5MTunXrptVYiIiIiIiICshOpCpVqgSVSgWVSoU6depoJFMPHz5ERkYGhg4dqtXgFi9ejIkTJ2L48OG4efMmnJyc8Omnn2LSpElSmbFjxyIzMxNDhgxBamoq3njjDezcuRPGxsZajYWIiIiIiKiASggh5BT88ccfIYTAoEGDsGDBAlhZWUn7DA0NUb169QrbnS49PR1WVlZIS0vjeCkieiXExDz+McwH0dL/o31QaPvjOzI/KrRCl2MjovJXuGOUwOM7qimPt0d7Pf4/30dIKbm5gewWqYJZ8tzc3PD666/DwMDg+aMkIiIiIiKqgGQlUunp6VI21qRJEzx48AAPHjwotixbdIiIiIiI6GUnK5GqVKkSbty4ATs7O1hbWxc72UTBJBQPHz7UepBERERERES6RFYiFRUVJc3IFxUVVWwiRURERERE9KqQlUh5eT0eseft7V1WsRAREREREVUIihfkDQ0NRURERJHtERER+PHHH7USFBERERERkS5TnEjNmjULlStXLrLdzs4OM2fO1EpQREREREREukxxInXlyhW4ubkV2e7q6oorV65oJSgiIiIiIiJdpjiRsrOzw4kTJ4psP378OGxtbbUSFBERERERkS5TnEj16dMHn332GaKjo/Hw4UM8fPgQUVFRGDlyJHr37l0WMRIREREREekUWbP2FTZ9+nRcunQJHTp0gL7+o4fn5+fjo48+4hgpIiIiIiJ6JShOpAwNDfHLL79g+vTpOH78OExMTNCwYUO4urqWRXxEREREREQ6R3EiVaBOnTqoU6eONmMhIiIiIiKqEEqVSP3777/YsmULrly5gpycHI198+bN00pgREREREREukpxIrV37168++67qFGjBs6ePQsPDw9cunQJQgg0bdq0LGIkIiIiIiLSKYpn7Rs/fjz+97//4e+//4axsTE2bNiAq1evwsvLCz179iyLGImIiIiIiHSK4kTqzJkz+OijjwAA+vr6ePDgAczNzTFt2jTMnj1b6wESERERERHpGsWJlJmZmTQuytHRERcvXpT23b59W3uRERERERER6SjFY6Rat26N/fv3w93dHW+99RZGjx6Nv//+G7/99htat25dFjESERERERHpFMWJ1Lx585CRkQEAmDp1KjIyMvDLL7+gdu3anLGPiIiIiIheCYoTqRo1akj/NzMzw4oVK7QaEBERERERka4r9YK8R44cwZkzZwAA9evXR7NmzbQWFBERERERkS5TnEj9+++/6NOnD/78809YW1sDAFJTU/H666/j559/RrVq1bQdIxERERERkU5RPGvfxx9/jNzcXJw5cwZ37tzBnTt3cObMGeTn5+Pjjz8uixiJiIiIiIh0iuIWqdjYWBw4cAB169aVttWtWxeLFy9G27ZttRocERERERGRLlLcIuXs7Izc3Nwi2x8+fAgnJyetBEVERERERKTLFCdSc+fOxYgRI3DkyBFp25EjRzBy5Eh88803Wg2OiIiIiIhIFynu2jdgwADcv38frVq1gr7+o4fn5eVBX18fgwYNwqBBg6Syd+7c0V6kREREREREOkJxIrVgwYIyCIOIiIiIiKjiUJxI9e/fvyziICIiIiIiqjBKvSAvAGRlZSEnJ0djm6Wl5XMFREREREREpOsUTzaRmZmJwMBA2NnZwczMDJUqVdK4ERERERERvewUJ1Jjx45FVFQUli9fDiMjI6xcuRJTp06Fk5MTVq9eXRYxEhERERER6RTFXfu2bt2K1atXw9vbGwMHDkTbtm1Rq1YtuLq6Yt26dejbt29ZxElERERERKQzFLdI3blzBzVq1ADwaDxUwRTnb7zxBvbt26fd6IiIiIiIiHSQ4kSqRo0aSEpKAgDUq1cP69evB/Copcra2lqrwREREREREekixYnUwIEDcfz4cQDAuHHjsHTpUhgbGyM4OBhjxozReoBERERERES6RvEYqeDgYOn/vr6+OHv2LBISElCrVi00atRIq8ERERERERHpIsUtUk9ydXVF9+7dyyyJunbtGj788EPY2trCxMQEDRs2xJEjR6T9QghMmjQJjo6OMDExga+vL86fP18msRAREREREQEKEqmoqCjUr18f6enpRfalpaWhQYMG+OOPP7Qa3N27d9GmTRsYGBhgx44dOH36NL799luN9armzJmDRYsWYcWKFTh48CDMzMzg5+eHrKwsrcZCRERERERUQHbXvgULFuCTTz6BpaVlkX1WVlb49NNPMW/ePLRt21Zrwc2ePRvOzs4IDQ2Vtrm5uUn/F0JgwYIF+PLLL9G1a1cAwOrVq2Fvb49Nmzahd+/eWouFiIiIiIiogOwWqePHj6NTp04l7u/YsSMSEhK0ElSBLVu2oHnz5ujZsyfs7OzQpEkT/PDDD9L+pKQkJCcnw9fXV9pmZWWFVq1aIS4ursR6s7OzkZ6ernEjIiIiIiKSS3YilZKSAgMDgxL36+vr49atW1oJqsA///yD5cuXo3bt2ti1axeGDRuGzz77DD/++CMAIDk5GQBgb2+v8Th7e3tpX3FmzZoFKysr6ebs7KzVuImIiIiI6OUmO5GqWrUqTp48WeL+EydOwNHRUStBFcjPz0fTpk0xc+ZMNGnSBEOGDMEnn3yCFStWPFe948ePR1pamnS7evWqliImIiIiItIOlerxjXSP7ETqrbfewsSJE4udxOHBgweYPHky3n77ba0G5+joiPr162tsc3d3x5UrVwAADg4OAB61lhWWkpIi7SuOkZERLC0tNW5ERC871VSVdCMiIqLnIzuR+vLLL3Hnzh3UqVMHc+bMwebNm7F582bMnj0bdevWxZ07dzBhwgStBtemTRskJiZqbDt37hxcXV0BPJp4wsHBAXv37pX2p6en4+DBg/D09NRqLERERERERAVkz9pnb2+PAwcOYNiwYRg/fjyEEAAAlUoFPz8/LF26tMhYpecVHByM119/HTNnzkSvXr1w6NAhfP/99/j++++lYwcFBeGrr75C7dq14ebmhokTJ8LJyQndunXTaixEREREREQFZCdSwKPFd3///XfcvXsXFy5cgBACtWvX1ljXSZtatGiBjRs3Yvz48Zg2bRrc3NywYMEC9O3bVyozduxYZGZmYsiQIUhNTcUbb7yBnTt3wtjYuExiIiIiIiIiUpRIFahUqRJatGih7ViK9fbbbz917JVKpcK0adMwbdq0FxIPERERERGR7DFSRERERERE9AgTKSIiIiIiIoWYSBERERERESnERIqIiIiIiEghJlJEREREREQKMZEiIiIiIiJSiIkUERERERGRQqVaR4qIiIiIXl4q1eP/C1F+cRDpMrZIERERERERKcREioiIiIiISCEmUkRERERERApxjBQREZU71dTHAzKivcoxECIiIpnYIkVERERERKQQEykiIiIiIiKF2LWPiIiIiEjXFZqTXjXl8ebC3aF9EP1om0/hbY/vCM5lr1VskSIiIiIiIlKIiRQREREREZFCTKSIiIiIiIgUYiJFRERERESkEBMpIiIiIiIihZhIERERERERKcREioiIiIiISCEmUkRERERERAoxkSIiIiIiIlKIiRQREREREZFCTKSIiIiIiIgU0i/vAIiIiIhIh6lUj/8vRPnFQaRj2CJFRERERESkEBMpIqKXmUr1+EZERERaw0SKiIiIiIhIISZSRERERERECjGRIiIiIiIiUoiJFBERERERkUJMpIiIiIiIiBRiIkVERERERKQQEykiIiIiIiKFmEgREREREREpxESKiIiIiIhIoQqVSH399ddQqVQICgqStmVlZSEgIAC2trYwNzeHv78/UlJSyi9IIiIiIiJ66VWYROrw4cP47rvv0KhRI43twcHB2Lp1KyIiIhAbG4vr16+je/fu5RQlERERERG9CipEIpWRkYG+ffvihx9+QKVKlaTtaWlpCAkJwbx589C+fXs0a9YMoaGhOHDgAOLj48sxYiIiIiIieplViEQqICAAXbp0ga+vr8b2hIQE5ObmamyvV68eXFxcEBcXV2J92dnZSE9P17gREVE5UKke3YiIiCoY/fIO4Fl+/vlnHD16FIcPHy6yLzk5GYaGhrC2ttbYbm9vj+Tk5BLrnDVrFqZOnartUImIiIiI6BWh0y1SV69exciRI7Fu3ToYGxtrrd7x48cjLS1Nul29elVrdRMRERER0ctPpxOphIQE3Lx5E02bNoW+vj709fURGxuLRYsWQV9fH/b29sjJyUFqaqrG41JSUuDg4FBivUZGRrC0tNS4ERERERERyaXTXfs6dOiAv//+W2PbwIEDUa9ePXz++edwdnaGgYEB9u7dC39/fwBAYmIirly5Ak9Pz/IImYiIiOilpZr6eEyjmCzKMRKi8qfTiZSFhQU8PDw0tpmZmcHW1lbaPnjwYIwaNQo2NjawtLTEiBEj4OnpidatW5dHyERERERE9ArQ6URKjvnz50OtVsPf3x/Z2dnw8/PDsmXLyjssIiIiIiJ6iVW4RComJkbjvrGxMZYuXYqlS5eWT0BERERERPTK0enJJoiIiIiIiHQREykiIiIiIiKFmEgREREREREpxESKiIiIiIhIISZSRERERERECjGRIiIiIiIiUoiJFBERERERkUJMpIiIiIiIiBRiIkVERERERKQQEykiIiIiIiKFmEgREREREREpxESKiIiIiIhIIf3yDoCIiLRLpXr8f1F+YRAREb3U2CJFRERERESkEBMpIiIiIiIihdi1j0iOgr5Sgh2liIiIACAm5nE/Ym9vfj7Sq4eJFJEWqGJipP8Lb+9yi4OIiIiIXgx27SMiIiIiIlKIiRQREREREZFCTKSIiIiIiIgUYiJFRERERESkECebIFJANfXxDEViMmcoIiIiInpVsUWKiIiIiIhIISZSRERERERECrFrHxERERGVKdXjnvFc255eGkykiCoQVaFPIsFPIiIiIqJyw0SKqAQav56VXxhEREREpIM4RoqIiIiIiEghJlJEREREREQKsWsfUSnFxBTq+4dordatiol5XLOPVqsmogqGYyOJiHQTEykiHVGWiRkRERERaRcTKSIiIiJ6cTgXOr0kOEaKiIiIiIhIISZSRERERERECrFrHxERERE9l8KTJAlv73KLg+hFYiJFREQvFBe7JiKilwG79hERERERESnERIqIiIiIiEghnU6kZs2ahRYtWsDCwgJ2dnbo1q0bEhMTNcpkZWUhICAAtra2MDc3h7+/P1JSUsopYiIiIiIiehXodCIVGxuLgIAAxMfHIzIyErm5uejYsSMyMzOlMsHBwdi6dSsiIiIQGxuL69evo3v37uUYNRERERHJoZqqgmqq6tkFiXSQTk82sXPnTo37YWFhsLOzQ0JCAtq1a4e0tDSEhIQgPDwc7du3BwCEhobC3d0d8fHxaN26dXmETURERERELzmdbpF6UlpaGgDAxsYGAJCQkIDc3Fz4+vpKZerVqwcXFxfExcWVWE92djbS09M1bkRERERERHLpdItUYfn5+QgKCkKbNm3g4eEBAEhOToahoSGsra01ytrb2yM5ObnEumbNmoWpU6eWZbhE9JJSFZq7WwhO3k1lI0YVU94hEBHRM1SYFqmAgACcPHkSP//883PXNX78eKSlpUm3q1evaiFCIiIiIiJ6VVSIFqnAwEBs27YN+/btQ7Vq1aTtDg4OyMnJQWpqqkarVEpKChwcHEqsz8jICEZGRmUZMr3CCv+S7C28yy0OIiIiIio7Ot0iJYRAYGAgNm7ciKioKLi5uWnsb9asGQwMDLB3715pW2JiIq5cuQJPT88XHS4REREREb0idLpFKiAgAOHh4di8eTMsLCykcU9WVlYwMTGBlZUVBg8ejFGjRsHGxgaWlpYYMWIEPD09OWMfEWkVx6wQEZWdmJjH40+9vTn+lCoGnU6kli9fDgDw9vbW2B4aGooBAwYAAObPnw+1Wg1/f39kZ2fDz88Py5Yte8GREhERERHRq0SnEyk5M2IZGxtj6dKlWLp06QuIiIiIiIiISMfHSBEREREREekinW6RIiIqT6qYGOn/0eUXBhEREekgtkgREREREREpxESKiIiIiIhIIXbtIyIiIiKted6F6Qt3qxZPzNxMpEuYSBGVIZXq8boYcmahpPJXeC0TjoyiF4lj8oiIKhYmUkREREREJAt/JH6MY6SIiIiIiIgUYiJFRERERESkEBMpIiIiIiIihThGioheeaqpj/t7R3uVYyBERERUYbBFioiIiIiISCG2SBHRq6nQrEOYUm5REBHRUzzvmlREZYmJFBERERERlahwQkuPMZEioldG4UaoV3vlCyIiInpeHCNFRERERESkEBMpIiIiIiIihdi1j4ioHKkK9TcU4uXucFj4XNm5koiIKjomUkTliOsXEb3aYmIKJ5fR5RYHEREpx0SKiOgF4+xHRETKsVWbdA0TKSIiIiIi0qCKiZH+z/by4jGRIiJ6AV7VDyS2vhER0cuKs/YREREREREpxBYpIqIywokEiOhVx3FN9DJjIqWDCr/nCDy+o5pSaPtkvhkR6SLOxEhERPRqYNc+ogpKpdJMuomIiIjoxWGLFBERadWrOrEGERG9WphIERERERERx/YqxK59RERERERECrFFqoIq/IuBtzcnniAqV4UHq00ptygAFJ4hi+8LREQvmsaEYXwbfukxkSIioufG7iDycWZHIqKXAxMpooqOP3+98mJUMeUdAhER0SuHiRQRvfRexgUhOTMeERFR+WIi9RIo/IVKeHuXWxxE5U0jufB5Acf7//zsRaVm7D5XgenQODoiekHYY+Slx0SKiCqckseYvHzJhS6Pp9Hl2IiISB6+l5cepz8nekFUqv//cargPxrdzeiZeN2IiIhIh7BFiuglUvCrkphcfl0ItNmTQaOu56uqYmE3sJfCK/v8JaqAHnfVfvzCVU15vL+gpaa0S84UbvUpz89o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hKmpqZgxY4ZwcHAQs2bNEnfu3FFUX2BgoLC1tRWtW7cWS5YsEbdv3xZCCKGvry9OnTqlqK46deqIQ4cOlbj/yJEjok6dOrLrc3R0FOfPny9x//nz54Wjo6OsumxsbDQSw6FDhwp/f3/pfnR0tKhevbrs2HJycsT69etFx44dhYmJiXjvvfdEREREqa6bqamp+Oeff6T77733nhgxYoR0/9SpU6JKlSqy60tJSRGzZ88WdevWFQ4ODiI4OFgcPny4VLFVr15dxMTESPfnzp0ratasKXJzc6X7rVq1kl2fNq/bk+7duyd++OEH0aZNG6FSqUT9+vWLtEI+jaGhYZFWSSMjI3H16tVSxaPN16qXl5fo06eP+Pvvv8X//vc/oVKpRJ06dURERESpYivJ9evXxaeffioMDAyEn5+frMeURSL11ltviffee++pNzmioqKEWq0WkydP1rje//33n5g4caLQ09MTsbGxpY71ec71WddNaSJV0DJ59uzZIvvOnDkj7O3txaJFi2TVdenSJemWlJQkzMzMpOSi8E0ubZ6rSqUSFy5cEGlpaU+9yVWrVi3x999/lxjb0aNHZX/OCPGo1XLfvn0l1rdz505Rv359WXVNmjRJuLi4FNv6d+zYMeHi4iImT54sOzYvLy8xYcKEEvdPmDBBeHl5yaqrSpUqIikpqcT9//zzj6hcubLs2MzNzcXly5dL3H/58mVhYWFRLrFVr15do2fOkSNHhL6+vvQ5qIS2P2e0/f77ww8/CFNTUxEdHS2EeJREvfHGG6JWrVri2rVriup66623hLGxsejatavYvHnzc/0oWdExkdIhderUEWFhYUKIR10SVCqV6NKli8jIyChVfXp6euKLL74Q6enpGttL88XW2Nj4qR+uly5dkt19o6C+p7WenD59WhgbG8uqy8TERCO2Ro0aafwKefnyZdl1CfHojbpt27biu+++0/iCVprrZmNjo/EYR0dHsXbtWun+xYsXFV+3Dz/8UOzcuVPjjUsbf9POnTtrtDomJibK7oonhHav29Ns27ZN2NjYKPoiqlari7SEmJubayS5SmjztVr4OXL//n2hVqvFpk2bShVXcdLT08WECROEubm5aNWqlYiKipL9WLVaLX2xTU1NFRYWFuL48eOl/mKrUqnE+++/LwYMGPDUmxy9evXS6Db7pE8++UT07t1bdmxP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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# vTotalCapCE\n", + "y2020_TotCap_CE=d_vars['vCETotCap'][d_vars['vCETotCap'].sYear=='y2020']\n", + "y2025_TotCap_CE=d_vars['vCETotCap'][d_vars['vCETotCap'].sYear=='y2025']\n", + "y2030_TotCap_CE=d_vars['vCETotCap'][d_vars['vCETotCap'].sYear=='y2030']\n", + "y2035_TotCap_CE=d_vars['vCETotCap'][d_vars['vCETotCap'].sYear=='y2035']\n", + "y2040_TotCap_CE=d_vars['vCETotCap'][d_vars['vCETotCap'].sYear=='y2040']\n", + "y2045_TotCap_CE=d_vars['vCETotCap'][d_vars['vCETotCap'].sYear=='y2045']\n", + "y2050_TotCap_CE=d_vars['vCETotCap'][d_vars['vCETotCap'].sYear=='y2050']\n", + "\n", + "# Avoid all the variables in sCE that begin with sPE2TE and sTE2TE\n", + "y2020_TotCap_CE = y2020_TotCap_CE[~y2020_TotCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2025_TotCap_CE = y2025_TotCap_CE[~y2025_TotCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2030_TotCap_CE = y2030_TotCap_CE[~y2030_TotCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2035_TotCap_CE = y2035_TotCap_CE[~y2035_TotCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2040_TotCap_CE = y2040_TotCap_CE[~y2040_TotCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2045_TotCap_CE = y2045_TotCap_CE[~y2045_TotCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2050_TotCap_CE = y2050_TotCap_CE[~y2050_TotCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2020_TotCap_CE = y2020_TotCap_CE[~y2020_TotCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2025_TotCap_CE = y2025_TotCap_CE[~y2025_TotCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2030_TotCap_CE = y2030_TotCap_CE[~y2030_TotCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2035_TotCap_CE = y2035_TotCap_CE[~y2035_TotCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2040_TotCap_CE = y2040_TotCap_CE[~y2040_TotCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2045_TotCap_CE = y2045_TotCap_CE[~y2045_TotCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2050_TotCap_CE = y2050_TotCap_CE[~y2050_TotCap_CE.sCE.str.startswith('sTE2TE')]\n", + "\n", + "\n", + "\n", + "# Delete the column sYear and make the index the column sCE\n", + "y2020_TotCap_CE = y2020_TotCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2025_TotCap_CE = y2025_TotCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2030_TotCap_CE = y2030_TotCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2035_TotCap_CE = y2035_TotCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2040_TotCap_CE = y2040_TotCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2045_TotCap_CE = y2045_TotCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2050_TotCap_CE = y2050_TotCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "\n", + "#graph the results in a bar chart for each technology\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "# Create a figure and a set of subplots\n", + "fig, ax = plt.subplots(1, 1, figsize=(10, 5))\n", + "\n", + "# Set the bar width\n", + "barWidth = 0.15\n", + "\n", + "# Set the position of the bars on the x-axis\n", + "r1 = np.arange(len(y2020_TotCap_CE))\n", + "r2 = [x + barWidth for x in r1]\n", + "r3 = [x + barWidth for x in r2]\n", + "r4 = [x + barWidth for x in r3]\n", + "r5 = [x + barWidth for x in r4]\n", + "r6 = [x + barWidth for x in r5]\n", + "r7 = [x + barWidth for x in r6]\n", + "r8 = [x + barWidth for x in r7]\n", + "r9 = [x + barWidth for x in r8]\n", + "\n", + "# Make the plot\n", + "plt.bar(r1, y2020_TotCap_CE.vCETotCap, color='b', width=barWidth, label='2020')\n", + "plt.bar(r2, y2025_TotCap_CE.vCETotCap, color='r', width=barWidth, label='2025')\n", + "plt.bar(r3, y2030_TotCap_CE.vCETotCap, color='g', width=barWidth, label='2030')\n", + "plt.bar(r4, y2035_TotCap_CE.vCETotCap, color='y', width=barWidth, label='2035')\n", + "plt.bar(r5, y2040_TotCap_CE.vCETotCap, color='c', width=barWidth, label='2040')\n", + "plt.bar(r6, y2045_TotCap_CE.vCETotCap, color='m', width=barWidth, label='2045')\n", + "plt.bar(r7, y2050_TotCap_CE.vCETotCap, color='k', width=barWidth, label='2050')\n", + "\n", + "# Add xticks on the middle of the group bars\n", + "plt.xlabel('Technologies', fontweight='bold')\n", + "plt.xticks([r + barWidth for r in range(len(y2020_TotCap_CE))], y2020_TotCap_CE.index, rotation=90)\n", + "plt.ylabel('Capacity [GW]')\n", + "plt.title('Total Capacity by Technology and Year')\n", + "# Create legend & Show graphic\n", + "plt.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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bN++HWPGjCl2mYCAAPj7+0vjaWlpsLGxUU/yRERERERULShdXIWEhODgwYNScbVq1So0b94cenp6AIBLly7BysoKfn5+ak2wsLC6fv06wsPDX9pDx4uMjY3RpEkTXLlypcQ2Ojo60NHRedVUiYiIiIioGlP6wUI//fQTxo8frzBty5YtiIiIQEREBBYtWoTt27erNbnCwury5cs4evQoateurXKM9PR0XL16FZaWlmrNjYiIiIiI6HlKF1dXrlxBy5YtpXFdXV2Fh7526NABFy5cUGnl6enpiIuLQ1xcHAAgISEBcXFxSExMRG5uLgYPHozTp0/jp59+Qn5+PpKSkpCUlIScnBwpRs+ePRUeXDxt2jRERUXh2rVriI6OxoABA6ChoQEvLy+VciMiIiIiIlKF0pcFpqSkKNxjde/ePYX5BQUFCvOVcfr0aYVnYxXe9zRy5EjMmzcP+/btAwC0adNGYbmIiAg4OzsDAK5evYr79+9L827evAkvLy88ePAApqam6Nq1K06dOgVTU1OVciMiIiIiIlKF0sWVtbU1zp07h6ZNmxY7/+zZs7C2tlZp5c7OzqU+FVqZJ0Zfu3ZNYXzr1q0q5UBERERERKQOSl8W+Pbbb2POnDnIysoqMi8zMxPz589H37591ZocERERERFRVaH0matZs2Zh+/btaNq0KXx9fdGkSRMAQHx8PFatWoW8vDzMmjWr3BIlIiIiIiKqzJQurszNzREdHY2JEydi5syZ0iV7MpkMvXr1wpo1a2Bubl5uiRIREREREVVmShdXAGBnZ4fQ0FA8fPhQem5Uo0aNYGJiUi7JERERERERVRUqFVeFTExM0KFDB3XnQkREREREVGUp1aHFwIEDkZaWpnTQ999/H3fv3i1zUkRERERERFWNUmeu9u7dW+S5ViURQmD//v1YuHAhzMzMXik5IiIiIiJ6dZGyyIpOoVpQqrgSQki9AxIREREREVFRShVXERERKgeuW7euyssQERERERFVVUoVVz169CjvPIiIiIiIiKo0pTq0ICIiIiIiotKxuCIiIiIiIlIDFldERERERERqwOKKiIiIiIhIDVQurubOnYvr16+XRy5ERERERERVlsrF1d69e9GwYUP07NkTW7ZsQXZ2dnnkRUREREREVKWoXFzFxcXhzz//RPPmzTF58mRYWFhg4sSJ+PPPP8sjPyIiIiIioiqhTPdctW3bFitWrMDt27exfv163Lx5E126dEGrVq2wfPlypKamqjtPoiotUhYpDURERET0ZnqlDi2EEMjNzUVOTg6EEKhVqxZWrVoFGxsbbNu2TV05EhERERERVXplKq5iY2Ph6+sLS0tL+Pn5oW3btrh48SKioqJw+fJlfPHFF/jkk0/UnSsREREREVGlpXJx1bJlS3Tq1AkJCQlYv349bty4ga+++gqNGjWS2nh5eeHevXtqTZSIiIiIiKgy01R1gaFDh2L06NGoW7duiW3q1KmDgoKCV0qMiIiIiIioKlH5zFXhvVUvyszMxIIFC9SSFBERERERUVWjcnE1f/58pKenF5n+5MkTzJ8/Xy1JERERERERVTUqXxYohIBMJisy/cyZMzAxMVFLUkREVLFkkZHS/yMqLg0iIqIqReniqlatWpDJZJDJZGjSpIlCgZWfn4/09HRMmDChXJIkIiIqDp8dR0RElYnSxdWyZcsghMDo0aMxf/58GBkZSfO0tbVRv359ODk5lUuSRERERERElZ3SxdXIkSMBAHZ2dujcuTO0tLTKLSkiIiIiIqKqRqniKi0tDYaGhgCAtm3bIjMzE5mZmcW2LWxHRERERERUnShVXNWqVQt37tyBmZkZjI2Ni+3QorCji/z8fLUnSUREREREVNkpVVyFh4dLPQGGh4cXW1wRERERERFVZ0oVVz169JD+7+zsXF65EBERERERVVkqP0Q4ODgYO3bsKDJ9x44d2Lhxo1qSIiIiIiIiqmpULq4CAwNRp06dItPNzMzw5ZdfqiUpIiIiIiKiqkbl4ioxMRF2dnZFptva2iIxMVGlWMePH8c777wDKysryGQy7NmzR2G+EAJz5syBpaUl9PT04ObmhsuXL7807urVq1G/fn3o6uqiY8eO+OOPP1TKi4iIiIiISFUqF1dmZmY4e/ZskelnzpxB7dq1VYqVkZGB1q1bY/Xq1cXO/+abb7BixQqsXbsWv//+O2rWrAkPDw9kZWWVGHPbtm3w9/fH3Llz8ddff6F169bw8PDA3bt3VcqNiIiIiIhIFSoXV15eXvjkk08QERGB/Px85OfnIzw8HJMnT8bw4cNVitWnTx98/vnnGDBgQJF5QggsW7YMs2fPRv/+/dGqVSv8+OOPuH37dpEzXM9bsmQJxo0bh1GjRqFZs2ZYu3YtatSogQ0bNpS4THZ2NtLS0hQGIiIiIiIiVahcXC1cuBAdO3ZEz549oaenBz09Pbi7u8PV1VWt91wlJCQgKSkJbm5u0jQjIyN07NgRMTExxS6Tk5OD2NhYhWXkcjnc3NxKXAZ4eh+ZkZGRNNjY2KhtO4iIiIiIqHpQubjS1tbGtm3bcOnSJfz000/YtWsXrl69ig0bNkBbW1ttiSUlJQEAzM3NFaabm5tL8150//595Ofnq7QMAAQEBCA1NVUabty48YrZExERERFRdaPUc66K06RJEzRp0kSduVQYHR0d6OjoVHQaRERERERUhZWpuLp58yb27duHxMRE5OTkKMxbsmSJWhKzsLAAACQnJ8PS0lKanpycjDZt2hS7TJ06daChoYHk5GSF6cnJyVI8IiIiIiKi8qBycXXs2DG8++67aNCgAS5duoQWLVrg2rVrEEKgXbt2akvMzs4OFhYWOHbsmFRMpaWl4ffff8fEiROLXUZbWxuOjo44duwYPD09AQAFBQU4duwYfH191ZYbERERERHRi1S+5yogIADTpk3DP//8A11dXfzyyy+4ceMGevTogSFDhqgUKz09HXFxcYiLiwPwtBOLuLg4JCYmQiaTYcqUKfj888+xb98+/PPPPxgxYgSsrKykwgkAevbsiVWrVknj/v7++OGHH7Bx40ZcvHgREydOREZGBkaNGqXqphIRERERESlN5TNXFy9exM8///x0YU1NZGZmQl9fHwsWLED//v1LPKtUnNOnT8PFxUUa9/f3BwCMHDkSISEhmDFjBjIyMjB+/HikpKSga9euCA0Nha6urrTM1atXcf/+fWl82LBhuHfvHubMmYOkpCS0adMGoaGhRTq5ICIiIiIiUieVi6uaNWtK91lZWlri6tWraN68OQAoFDnKcHZ2hhCixPkymQwLFizAggULSmxz7dq1ItN8fX15GSAREREREb1WKhdXnTp1wokTJ+Dg4IC3334bU6dOxT///INdu3ahU6dO5ZEjERERERFRpadycbVkyRKkp6cDAObPn4/09HRs27YNjRs3VltPgURERERERFWNysVVgwYNpP/XrFkTa9euVWtCREREREREVVGZHyJ8+vRpXLx4EQDQrFkzODo6qi0pIiIiIiKiqkbl4urmzZvw8vLCyZMnYWxsDABISUlB586dsXXrVlhbW6s7RyIiIiIiokpP5edcjR07Frm5ubh48SIePnyIhw8f4uLFiygoKMDYsWPLI0ciIiIiIqJKT+UzV1FRUYiOjkbTpk2laU2bNsXKlSvRrVs3tSZHRERERERUVah85srGxga5ublFpufn58PKykotSREREREREVU1KhdXixYtwqRJk3D69Glp2unTpzF58mR8++23ak2OiIiIiIioqlD5skBvb288efIEHTt2hKbm08Xz8vKgqamJ0aNHY/To0VLbhw8fqi9TIiIiIiKiSkzl4mrZsmXlkAYREREREVHVpnJxNXLkyPLIg4iIiIiIqEor80OEASArKws5OTkK0wwNDV8pISIiIiIioqpI5Q4tMjIy4OvrCzMzM9SsWRO1atVSGIiIiIiIiKojlYurGTNmIDw8HEFBQdDR0cG6deswf/58WFlZ4ccffyyPHImIiIiIiCo9lS8L3L9/P3788Uc4Oztj1KhR6NatGxo1agRbW1v89NNPeP/998sjTyIiIiIiokpN5TNXDx8+RIMGDQA8vb+qsLv1rl274vjx4+rNjoiIiIiIqIpQubhq0KABEhISAAD29vbYvn07gKdntIyNjdWaHBERERERUVWhcnE1atQonDlzBgAwc+ZMrF69Grq6uvDz88P06dPVniAREREREVFVoPI9V35+ftL/3dzccOnSJcTGxqJRo0Zo1aqVWpMjIiIiIiKqKl7pOVcAYGtrC1tbW3XkQkREREREVGUpfVlgeHg4mjVrhrS0tCLzUlNT0bx5c/z2229qTY6IiIiIiKiqULq4WrZsGcaNGwdDQ8Mi84yMjPDRRx9hyZIlak2OiIiIiIioqlC6uDpz5gx69+5d4nx3d3fExsaqJSkiIiIiIqKqRuniKjk5GVpaWiXO19TUxL1799SSFBERERERUVWjdHFVt25dnDt3rsT5Z8+ehaWlpVqSIiIiIiIiqmqULq7efvttfPbZZ8jKyioyLzMzE3PnzkW/fv3UmhwREREREVFVoXRX7LNnz8auXbvQpEkT+Pr6omnTpgCAS5cuYfXq1cjPz8enn35abokSERERERFVZkoXV+bm5oiOjsbEiRMREBAAIQQAQCaTwcPDA6tXr4a5uXm5JUpERERERFSZqfQQYVtbWxw6dAiPHj3ClStXIIRA48aNUatWrfLKj4iIiIiIqEpQqbgqVKtWLbRv317duRAREREREVVZSndoQURERERERCUr05krIiIiIqo+ZLJn/xd4NiKb92x6RI9n/3dBxLPpLs9PfzZSeP8+0Zuk0p+5ql+/PmQyWZHBx8en2PYhISFF2urq6r7mrImIiIiIqLqp9Geu/vzzT+Tn50vj586dQ69evTBkyJASlzE0NER8fLw0Lnv+5xYiIiIiIqJyUOmLK1NTU4Xxr776Cg0bNkSPHj1KWOJpMWVhYVHeqREREREREUkq/WWBz8vJycHmzZsxevToUs9Gpaenw9bWFjY2Nujfvz/Onz9fatzs7GykpaUpDERERERERKqoUsXVnj17kJKSAm9v7xLbNG3aFBs2bMDevXuxefNmFBQUoHPnzrh582aJywQGBsLIyEgabGxsyiF7IiIiIiJ6k1Wp4mr9+vXo06cPrKysSmzj5OSEESNGoE2bNujRowd27doFU1NTfPfddyUuExAQgNTUVGm4ceNGeaRPRERERERvsEp/z1Wh69ev4+jRo9i1a5dKy2lpaaFt27a4cuVKiW10dHSgo6PzqikSEREREVE1VmXOXAUHB8PMzAx9+/ZVabn8/Hz8888/sLS0LKfMiIiIiIiIqkhxVVBQgODgYIwcORKamoon20aMGIGAgABpfMGCBThy5Aj+++8//PXXX/jggw9w/fp1jB079nWnTURERERE1UiVuCzw6NGjSExMxOjRo4vMS0xMhFz+rEZ89OgRxo0bh6SkJNSqVQuOjo6Ijo5Gs2bNXmfKRERERERUzVSJ4srd3R1CiGLnRUZGKowvXboUS5cufQ1ZERERERERPVMliisiIno1zz8aUODZiGzes+kRCs9mjyjvlIiIiN44VeKeKyIiIiIiosqOZ66IqjDZc6cjSrp0loiIiIheD565IiIiIiIiUgMWV0RERERERGrA4oqIiIiIiEgNWFwRERERERGpAYsrIiIiIiIiNWBxRUREREREpAYsroiIiIiIiNSAz7kiUtJzj5SCwLMR2bxn0yN6PPu/CyKeTS/HvIiIiIiocuCZKyIiIiIiIjVgcUVERERERKQGLK6IiIiIiIjUgMUVERERERGRGrC4IiIiIiIiUgMWV0RERERERGrA4oqIiIiIiEgNWFwRERERERGpAYsrIiIiIiIiNWBxRUREREREpAYsroiIiIiIiNSAxRUREREREZEasLgiIiIiIiJSAxZXREREREREasDiioiIiIiISA1YXBEREREREakBiysiIiIiIiI1YHFFRERERESkBiyuiIiIiIiI1IDFFRERERERkRqwuCIiIiIiIlIDFldERERERERqwOKKiIiIiIhIDSp1cTVv3jzIZDKFwd7evtRlduzYAXt7e+jq6qJly5Y4dOjQa8qWiIiIiIiqs0pdXAFA8+bNcefOHWk4ceJEiW2jo6Ph5eWFMWPG4O+//4anpyc8PT1x7ty515gxERERERFVR5W+uNLU1ISFhYU01KlTp8S2y5cvR+/evTF9+nQ4ODhg4cKFaNeuHVatWvUaMyYiIiIiouqo0hdXly9fhpWVFRo0aID3338fiYmJJbaNiYmBm5ubwjQPDw/ExMSUuo7s7GykpaUpDERERERERKqo1MVVx44dERISgtDQUAQFBSEhIQHdunXD48ePi22flJQEc3NzhWnm5uZISkoqdT2BgYEwMjKSBhsbG7VtAxERERERVQ+Vurjq06cPhgwZglatWsHDwwOHDh1CSkoKtm/frtb1BAQEIDU1VRpu3Lih1vhERERERPTm06zoBFRhbGyMJk2a4MqVK8XOt7CwQHJyssK05ORkWFhYlBpXR0cHOjo6asuTiIiIiIiqn0p95upF6enpuHr1KiwtLYud7+TkhGPHjilMCwsLg5OT0+tIj4iIiIiIqrFKXVxNmzYNUVFRuHbtGqKjozFgwABoaGjAy8sLADBixAgEBARI7SdPnozQ0FAsXrwYly5dwrx583D69Gn4+vpW1CYQEREREVE1UakvC7x58ya8vLzw4MEDmJqaomvXrjh16hRMTU0BAImJiZDLn9WHnTt3xpYtWzB79mzMmjULjRs3xp49e9CiRYuK2gQiIiIiIqomKnVxtXXr1lLnR0ZGFpk2ZMgQDBkypJwyIiIiIiIiKl6lviyQiIiIiIioqmBxRUREREREpAYsroiIiIiIiNSAxRUREREREZEasLgiIiIiIiJSAxZXRK+ZTCaDTCar6DSIiIiISM1YXBEREREREakBiysiIiIiIiI1YHFFRERERESkBiyuiIiIiIiI1IDFFRERERERkRqwuCIiIiIiIlIDFldERERERERqwOKKiIiIiIhIDVhcERERERERqQGLKyIiIiIiIjVgcUVERERERKQGLK6IiIiIiIjUgMUVERERERGRGrC4IiIiIiIiUgMWV0RERERERGrA4oqIiIiI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u3v3LkJCQrBhwwakpqbCy8sLkZGRcHJywujRo1V+ptHVq1elN76BAwdCU1MTixYtKtM9DmfOnMHXX39d4nx3d3eVLleMj4/Htm3bpMtlpk6dijlz5uDu3btlekPT0NDA7du3S/yAv337ttJvQr/++itCQkLg6uoKX19fNGjQAG3atMGXX36pcl7A044Z4uPjSyyuLl26pPTlZMePH8euXbvQqVMnDB06FBYWFnj//fcxZcqUMuWWnJxc6n1NmpqaSn35A9S/35Rx69Yt1K1b96XtevbsifXr1+Pu3bv48MMP4eHh8Urdgi9YsADa2tq4evVqkcvYFixYAHd3dyxYsECpG8jXrl2LsWPHYt68eQrTTUxMsGDBAiQlJSEoKEjp4urgwYP45JNPMGXKFEydOlXq9v/OnTtYtGgRJk+ejPr16+Ptt99WKp5Q83OucnJycOrUKUREREhf2GxsbNC9e3esWrVK6XvBABTpQvh5MpkMGRkZyMvLU/pZV893iV8SZW/azsjIKPXHnMePHyt9iWxpl4k9fvwYW7ZsUalrd0B93eLn5eXh3r17Jb733rt3T6Xu2PPy8hTuW4qJiVF4f7OyspIuw32Zkgq6J0+eYPny5VixYoVKX3hLe5+9du0avvvuO6X/Dn///fdL26jyNyqP+wp1dHSky3WBp/fXRUdH49dff8X333+P77//Xqni6p9//sGiRYtKnN+nTx+Vvj8oUzQp68mTJwo/DGlra0NXVxfp6ell/vHh8OHDCj3HFhQU4NixYzh37pw0TZkOwDZs2ICUlBSFQnz8+PFYv349gKePBjh8+HCZ7h18Vc2aNcOJEyekR5B8/PHHWLBggfRd5u7du6hfv77S73FVHYurSszW1haDBw/G8uXL0atXr1f+RSIzM1PqaEImk0FHR0fh+UqqUOeXcED9b2jqfEjh7du3pV9N69evD11d3Ve6L8LNzQ1ffPFFsfeUCSHwxRdfwM3NTalYycnJUpFmZmaGGjVqlPnB0ABQt25dnDt3TvrV7kVnz55V+phR934rTVJSEr744gusX79eqTfvw4cP48aNGwgODsbEiRORmZmJYcOGASjbl8w9e/bgu++++7/2zjssquP7/+9dioA020ckihUBxRp7VMCCvYA1RmMXWxILii1YIhbsBltUxIpd0RjFBlhQsBMLNhRNBNQIKoggcH5/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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Decommisioned capcity by technology and year\n", + "y2020_TotCap_CE=d_vars['vCEDecCap'][d_vars['vCEDecCap'].sYear=='y2020']\n", + "y2025_TotCap_CE=d_vars['vCEDecCap'][d_vars['vCEDecCap'].sYear=='y2025']\n", + "y2030_TotCap_CE=d_vars['vCEDecCap'][d_vars['vCEDecCap'].sYear=='y2030']\n", + "y2035_TotCap_CE=d_vars['vCEDecCap'][d_vars['vCEDecCap'].sYear=='y2035']\n", + "y2040_TotCap_CE=d_vars['vCEDecCap'][d_vars['vCEDecCap'].sYear=='y2040']\n", + "y2045_TotCap_CE=d_vars['vCEDecCap'][d_vars['vCEDecCap'].sYear=='y2045']\n", + "y2050_TotCap_CE=d_vars['vCEDecCap'][d_vars['vCEDecCap'].sYear=='y2050']\n", + "\n", + "# Avoid all the variables in sCE that begin with sPE2TE and sTE2TE\n", + "y2020_TotCap_CE = y2020_TotCap_CE[~y2020_TotCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2025_TotCap_CE = y2025_TotCap_CE[~y2025_TotCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2030_TotCap_CE = y2030_TotCap_CE[~y2030_TotCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2035_TotCap_CE = y2035_TotCap_CE[~y2035_TotCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2040_TotCap_CE = y2040_TotCap_CE[~y2040_TotCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2045_TotCap_CE = y2045_TotCap_CE[~y2045_TotCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2050_TotCap_CE = y2050_TotCap_CE[~y2050_TotCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2020_TotCap_CE = y2020_TotCap_CE[~y2020_TotCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2025_TotCap_CE = y2025_TotCap_CE[~y2025_TotCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2030_TotCap_CE = y2030_TotCap_CE[~y2030_TotCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2035_TotCap_CE = y2035_TotCap_CE[~y2035_TotCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2040_TotCap_CE = y2040_TotCap_CE[~y2040_TotCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2045_TotCap_CE = y2045_TotCap_CE[~y2045_TotCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2050_TotCap_CE = y2050_TotCap_CE[~y2050_TotCap_CE.sCE.str.startswith('sTE2TE')]\n", + "\n", + "# Delete the column sYear and make the index the column sCE\n", + "y2020_TotCap_CE = y2020_TotCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2025_TotCap_CE = y2025_TotCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2030_TotCap_CE = y2030_TotCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2035_TotCap_CE = y2035_TotCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2040_TotCap_CE = y2040_TotCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2045_TotCap_CE = y2045_TotCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2050_TotCap_CE = y2050_TotCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "\n", + "#graph the results in a bar chart for each technology\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "# Create a figure and a set of subplots\n", + "fig, ax = plt.subplots(1, 1, figsize=(10, 5))\n", + "\n", + "# Set the bar width\n", + "barWidth = 0.15\n", + "\n", + "# Set the position of the bars on the x-axis\n", + "r1 = np.arange(len(y2020_TotCap_CE))\n", + "r2 = [x + barWidth for x in r1]\n", + "r3 = [x + barWidth for x in r2]\n", + "r4 = [x + barWidth for x in r3]\n", + "r5 = [x + barWidth for x in r4]\n", + "r6 = [x + barWidth for x in r5]\n", + "r7 = [x + barWidth for x in r6]\n", + "r8 = [x + barWidth for x in r7]\n", + "r9 = [x + barWidth for x in r8]\n", + "\n", + "# Make the plot\n", + "plt.bar(r1, y2020_TotCap_CE.vCEDecCap, color='b', width=barWidth, label='2020')\n", + "plt.bar(r2, y2025_TotCap_CE.vCEDecCap, color='r', width=barWidth, label='2025')\n", + "plt.bar(r3, y2030_TotCap_CE.vCEDecCap, color='g', width=barWidth, label='2030')\n", + "plt.bar(r4, y2035_TotCap_CE.vCEDecCap, color='y', width=barWidth, label='2035')\n", + "plt.bar(r5, y2040_TotCap_CE.vCEDecCap, color='c', width=barWidth, label='2040')\n", + "plt.bar(r6, y2045_TotCap_CE.vCEDecCap, color='m', width=barWidth, label='2045')\n", + "plt.bar(r7, y2050_TotCap_CE.vCEDecCap, color='k', width=barWidth, label='2050')\n", + "\n", + "# Add xticks on the middle of the group bars\n", + "plt.xlabel('Technologies', fontweight='bold')\n", + "plt.xticks([r + barWidth for r in range(len(y2020_TotCap_CE))], y2020_TotCap_CE.index, rotation=90)\n", + "plt.ylabel('Capacity [GW]')\n", + "plt.title('Decommisioned Capacity by Technology and Year')\n", + "# Create legend & Show graphic\n", + "plt.legend()\n", + "plt.show()\n" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 17, "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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h6ste/78efHOO+8IKysrYWxsLBo2bCimTJkizS9tCPDk5GTRvXt3YW5uLgCUOhy4p6enUCqV4p9//pG1rzTZvmInT54UAETXrl1lreNxLi4uonv37iWm//7776JXr17CxsZGGBkZCRcXF9G3b19x6NAhaZn79++LwYMHixo1aggzMzPh7+8vLl++XGIY6Se9Z0tTVFQkZs2aJVxcXISRkZFo3ry52L17txg4cKDacN3Fw2XPmTOnRAwAYtq0aWrTtm3bJjw8PISRkZFo1KiR2L59e4mYcjw+BLgQQqSkpIjAwEDh5OQkDAwMhL29vejUqZNYtWqV2nIPHz4UkyZNEq6urtJyvXv3FlevXtV4mwYOHChMTU1LLDdt2jTx+KHKgwcPREhIiHB0dBQGBgaiQYMGYs6cOWrDvAtRcghwIYS4evWq6N27t/T5aNWqVan3Sfv7779F9+7dhYmJibC1tRWjR48W27ZtEwBEXFxcieUr+t4loqpHIcQz6A1KRERqoqOj4efnhy1btqB37966TuepmjdvDmtra6kvV2U4e/YsmjVrhrVr12rU74noWVi4cCFCQkLwzz//oFatWmrz+N4levGwTxIRET3R6dOncebMGbWBIyrDd999BzMzM/Tq1atS10P0NNnZ2WrPc3JysHLlSjRo0KBEgQTwvUv0ImKfJCIiKtX58+cRHx+PefPmwcHBAf369auU9ezatQsXL17EqlWrEBQUBFNT00pZD5FcvXr1grOzM5o1a4b09HSsX78ely9fVruxMsD3LtGLjEUSERGVauvWrZgxYwYaNmyITZs2SR3XtW3UqFFISUnBG2+8genTp1fKOog04e/vj9WrV2PDhg0oLCxEo0aN8MMPP5Q4UcD3LtGLi32SiIiIiIiIVLBPEhERERERkQoWSURERERERCpe+D5JRUVFSEpKgrm5eYkbwBERERER0ctDCIEHDx7A0dFRuol0aV74IikpKQlOTk66ToOIiIiIiKqImzdvonbt2mXOf+GLJHNzcwCPdoSFhYWOsyEiIiIiIl3JyMiAk5OTVCOU5YUvkoovsbOwsGCRRERERERET+2Gw4EbiIiIiIiIVLBIIiIiIiIiUsEiiYiIiIiISMUL3yeJiIiIiKiqE0KgoKAAhYWFuk7luaanpwd9ff0K3/qHRRIRERERkQ7l5eXh9u3bePjwoa5T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LwcA+D52C4fw8HAMGjQIwKO+RkqlEgEBAcjNzYW/vz+WLVsmLWtiYoLvvvsOISEhyM3NhZOTE3r16oUJEyZIy7i6umLPnj0ICQnBokWLULt2baxevRr+/v6Vun28TxIREekM75NERC+7J93Th8qH90kiIiIiIiLSMhZJREREREREKlgkERERERERqWCRREREREREpIJFEhERERERkQoWSURERERERCpYJBEREREREalgkURERERERKSCRRIREREREZEKfV0nQEREz0a0Ilr62w9+0t9CCB1kQ0RETxMdrXhm6/L15W+BKrYkERERERGRRmbPno2WLVvC3NwcdnZ26NmzJxISEtSWycnJQWBgIGxsbGBmZoaAgACkpKRI8+/du4fXX38djo6OMDIygpOTE4KCgpCRkSEtEx0dDYVCUeKRnJxcqdvHIomIiIiIiDQSExODwMBAxMXF4cCBA8jPz0fXrl2RlZUlLRMSEoJdu3Zhy5YtiImJQVJSEnr16iXNVyqV6NGjB37++Wf8+eefiIiIwMGDBzFixIgS60tISMDt27elh52dXaVuHy+3IyIiIiIijezdu1fteUREBOzs7BAfH48OHTogPT0dYWFh2LhxIzp27AgACA8Ph4eHB+Li4tCmTRtUr14dI0eOlGK4uLjg448/xpw5c0qsz87ODlZWVpW6TarYkkRERERERBWSnp4OALC2tgYAxMfHIz8/H507d5aWcXd3h7OzM2JjY0uNkZSUhO3bt8PHx6fEvGbNmsHBwQFdunTBsWPHKmEL1LFIIiIiIiKicisqKkJwcDDatm2Lxo0bAwCSk5NhaGhYovWnZs2aJfoTDRgwANWqVUOtWrVgYWGB1atXS/McHBywYsUKbNu2Ddu2bYOTkxN8fX3x22+/Veo2sUgiIiIiIqJyCwwMxPnz5/HDDz+U6/ULFizAb7/9hp07d+Lq1asIDQ2V5jVs2BD/+9//4OXlhddeew1r1qzBa6+9hgULFmgr/VKxTxIREREREZVLUFAQdu/ejcOHD6N27drSdHt7e+Tl5SEtLU2tNSklJQX29vZqMezt7WFvbw93d3dYW1ujffv2mDJlChwcHEpdZ6tWrXD06NFK2Z5ibEkiIiIiIiKNCCEQFBSEHTt2IDIyEq6urmrzvby8YGBggEOHDknTEhIScOPGDXh7e5cZt6ioCACQm5tb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a+jUqRP09R+9vKioCB9++CH7JBERERER0XNP4yLJ0NAQP/74I7744gucPXsWJiYmaNKkCVxcXCojPyIiIiIiomdK4yKpmJubG9zc3LSZCxERERERkc6Vq0j6559/8PPPP+PGjRvIy8tTmzd//nytJEZERERERKQLGhdJhw4dwttvv426devi8uXLaNy4Ma5duwYhBFq0aFEZORIRERERET0zGo9uN3HiRIwZMwZ//PEHjI2NsW3bNty8eRM+Pj7o06dPZeRIRERERET0zGhcJF26dAkffvghAEBfXx/Z2dkwMzPDjBkz8PXXX2s9QSIiIiIiomdJ4yLJ1NRU6ofk4OCAq1evSvPu3r2rvcyIiIiIiIh0QOM+SW3atMHRo0fh4eGBN954A6NHj8Yff/yB7du3o02bNpWRIxERERER0TOjcZE0f/58ZGZmAgCmT5+OzMxM/Pjjj2jQoAFHtiMiIiIioueexkVS3bp1pb9NTU2xYsUKrSZERERERESkS+W+mezp06dx6dIlAECjRo3g5eWltaSIiIiIiIh0ReMi6Z9//sGAAQNw7NgxWFlZAQDS0tLw2muv4YcffkDt2rW1nSMREREREdEzo/HodsOGDUN+fj4uXbqE1NRUpKam4tKlSygqKsKwYcMqI0ciIiIiIqJnRuOWpJiYGBw/fhwNGzaUpjVs2BDffvst2rdvr9XkiIiIiIiInjWNW5KcnJyQn59fYnphYSEcHR21khQREREREZGuaFwkzZkzB6NGjcLp06elaadPn8ann36KuXPnajU5IiIiIiKiZ03jy+0GDRqEhw8fonXr1tDXf/TygoIC6OvrY8iQIRgyZIi0bGpqqvYyJSIiIiIiegY0LpIWLlxYCWkQERERERFVDRoXSQMHDqyMPIiIiIiIiKqEct9MFgBycnKQl5enNs3CwqJCCREREREREemSxgM3ZGVlISgoCHZ2djA1NUX16tXVHkRERERERM8zjYukcePGITIyEsuXL4eRkRFWr16N6dOnw9HREWvXrq2MHImIiIiIiJ4ZjS+327VrF9auXQtfX18MHjwY7du3R/369eHi4oINGzbgvffeq4w8iYiIiIiIngmNW5JSU1NRt25dAI/6HxUP892uXTscPnxYu9kRERER0UtDofjvQaRLGhdJdevWRWJiIgDA3d0dmzdvBvCohcnKykqryRERERERET1rGl9uN3jwYJw9exY+Pj6YMGEC3nrrLSxZsgT5+fmYP39+ZeRIRERERPRSUEz/rxlNTBM6zOTlpnGRFBISIv3duXNnXL58GfHx8ahfvz6aNm2q1eSIiIiIiIietQrdJwkAXFxc4OLioo1ciIiIiIiIdE52n6TIyEg0atQIGRkZJealp6fD09MTR44c0WpyREREREREz5rsImnhwoX46KOPYGFhUWKepaUl/ve//7FPEhERERERPfdkF0lnz57F66+/Xub8rl27Ij4+XitJERHRi0UxXSE9iIiIqjrZRVJKSgoMDAzKnK+vr487d+5otPLZs2ejZcuWMDc3h52dHXr27ImEhAS1ZXJychAYGAgbGxuYmZkhICAAKSkpGq2HiOiFpXJTERYiRERE2iG7SKpVqxbOnz9f5vxz587BwcFBo5XHxMQgMDAQcXFxOHDgAPLz89G1a1dkZWVJy4SEhGDXrl3YsmULYmJikJSUhF69emm0HiIiIiIiIrlkj273xhtvYMqUKXj99ddhbGysNi87OxvTpk3Dm2++qdHK9+7dq/Y8IiICdnZ2iI+PR4cOHZCeno6wsDBs3LgRHTt2BACEh4fDw8MDcXFxaNOmjUbrIyIiIiIiehrZRdLkyZOxfft2uLm5ISgoCA0bNgQAXL58GUuXLkVhYSEmTZpUoWTS09MBANbW1gCA+Ph45Ofno3PnztIy7u7ucHZ2RmxsbKlFUm5uLnJzc6XnpY3GR0REREREVBbZRVLNmjVx/PhxjBw5EhMnToQQj+4ArFAo4O/vj6VLl6JmzZrlTqSoqAjBwcFo27YtGjduDABITk6GoaEhrKysSuSSnJxcapzZs2dj+vTp5c6DiIiIiIhebhrdTNbFxQW//PIL7t+/jytXrkAIgQYNGqB69eoVTiQwMBDnz5/H0aNHKxRn4sSJCA0NlZ5nZGTAycmpoukRERERET1T0dH/DcTj6yt0mMnLR6MiqVj16tXRsmVLrSURFBSE3bt34/Dhw6hdu7Y03d7eHnl5eUhLS1NrTUpJSYG9vX2psYyMjGBkZKS13IiIiIiI6OUie3S7yiCEQFBQEHbs2IHIyEi4urqqzffy8oKBgQEOHTokTUtISMCNGzfg7e39rNMlIiIiIqKXQLlakrQlMDAQGzduxM6dO2Fubi71M7K0tISJiQksLS0xdOhQhIaGwtraGhYWFhg1ahS8vb05sh0REREREVUKnRZJy5cvBwD4+vqqTQ8PD8egQYMAAAsWLIBSqURAQAByc3Ph7++PZcuWPeNMiYiIiIjoZaHTIql4hLwnMTY2xtKlS7F06dJnkBEREREREb3sdNoniYiIiIiIqKphkURERERERKSCRRIREREREZEKFklEREREREQqWCQRERERERGpYJFERERERESkgkUSERERERGRChZJREREREREKlgkERERERERqWCRREREREREpIJFEhERERERkQoWSURERERERCpYJBEREREREalgkURERERERKSCRRIREREREZEKFklEREREREQqWCQRERERERGpYJFERERERESkgkUSERERERGRChZJREREREREKlgkERERERERqWCRREREREREpIJFEhERERERkQp9XSdAREQvDoXiv7+F7tIgIiKqELYkERERERERqWCRREREREREpIJFEhERERERkQoWSURERERERCpYJBEREREREalgkURERERERKSCRRIREREREZEKFklEREREREQqWCQRERERERGpYJFERERERESkgkUSERERERGRChZJREREREREKlgkERERERERqdDXdQJELyrFdIX0d5SPDhMhIiIiIo2wJYmIiIiIiEgFiyQiIiIiIiIVLJKIiIiIiIhUsEgiIiIiIiJSwSKJiIiIiIhIBYskIiIiIiIiFSySiIiIiIiIVLBIIiIiIiIiUsEiiYiIiIiISAWLJCIiIiIiIhUskoiIiIiIiFSwSCIiIiIiIlLBIomIiIiIiEgFiyQiIiIiIiIVLJKIiIiIiIhUsEgiIiIiIiJSwSKJiIiIiIhIBYskIiIiIiIiFSySiIiIiIiIVLBIIiIiIiIiUsEiiYiIiIiISIW+rhMg0jmF4r+/haj81UVH/7c6X99KXx+9eNTesrpLg4iI6IXFliQiIiIiIiIVOi2SDh8+jLfeeguOjo5QKBT46aef1OYLITB16lQ4ODjAxMQEnTt3xl9//aWbZImIiIiI6KWg0yIpKysLr7zyCpYuXVrq/G+++QaLFy/GihUrcOLECZiamsLf3x85OTnPOFMiIiIiInpZ6LRPUrdu3dCtW7dS5wkhsHDhQkyePBk9evQAAKxduxY1a9bETz/9hP79+5f6utzcXOTm5krPMzIytJ84ERERERG9sKpsn6TExEQkJyejc+fO0jRLS0u0bt0asbGxZb5u9uzZsLS0lB5OTk7PIl0iIiIiInpBVNkiKTk5GQBQs2ZNtek1a9aU5pVm4sSJSE9Plx43b96s1DyJiIhKEx2tkB5ERPR8eeGGADcyMoKRkZGu0yAiIiIioudUlS2S7O3tAQApKSlwcHCQpqekpKBZs2Y6yoqIiCpKvWUlSmd5EBERlaXKXm7n6uoKe3t7HDp0SJqWkZGBEydOwNvbW4eZERERERHRi0ynLUmZmZm4cuWK9DwxMRFnzpyBtbU1nJ2dERwcjC+//BINGjSAq6srpkyZAkdHR/Ts2VN3SRMRERER0QtNp0XS6dOn4efnJz0PDQ0FAAwcOBAREREYN24csrKyMHz4cKSlpaFdu3bYu3cvjI2NdZUyERERERG94HRaJPn6+kIIUeZ8hUKBGTNmYMaMGc8wKyIiIiIieplV2T5JREREREREusAiiYiIiIiISAWLJCIiIiIiIhUskoiIiIiIiFSwSCIiIiIiIlLBIomIiIiIiEgFiyQiIiIiIiIVLJKIiIiIiIhUsEgiIiIiIiJSwSKJiIiIiIhIBYskIiIiIiIiFSySiIiIiIiIVLBIIiIiIiIiUsEiiYiIiIiISAWLJCIiIiIiIhUskoiIiIiIiFSwSCIiIiIiIlKhr+sEiHRBofjvb6G7NIiIiIioCmJLEhERERERkQq2JBGpUEz/r4kpykeHiRARERGRzrAliYiIiIiISAWLJCIiIiIiIhUskoiIiIiIiFSwSCIiIiIiIlLBIomIiIiIiEgFiyQiIiIiIiIVLJKIiIiIiIhUsEgiIiIiIiJSwZvJEhERVTJFdLT0d5Tff9P98N8TIcQzzIiIiJ6ELUlEREREREQqWCQRERERERGpYJFERERERESkgn2SiLRJofjv7891lgURERGRLNGKaOlv9pP8D1uSiIiIiIiIVLAliYioHKKj/2s19PV9uc+2ERERvWjYkkRERERERKSCRRIREREREZEKFklEREREREQqWCQRERERERGpYJFERERERESkgqPbERFRuZR1bw2Ao/0REdHzjS1JREREREREKlgkERERERERqeDldkRERERELzjVm6D7IUr6O6q0hYktSURERERERKpYJBEREREREalgkURERERERKSCRRIREREREZEKFklEREREREQqOLodEb3QFNP/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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ - "### Create the instance of the abstract model " + "# New capacity installed by technology and year\n", + "y2020_TotCap_CE = d_vars['vCENewCap'][d_vars['vCENewCap'].sYear=='y2020']\n", + "y2025_TotCap_CE = d_vars['vCENewCap'][d_vars['vCENewCap'].sYear=='y2025']\n", + "y2030_TotCap_CE = d_vars['vCENewCap'][d_vars['vCENewCap'].sYear=='y2030']\n", + "y2035_TotCap_CE = d_vars['vCENewCap'][d_vars['vCENewCap'].sYear=='y2035']\n", + "y2040_TotCap_CE = d_vars['vCENewCap'][d_vars['vCENewCap'].sYear=='y2040']\n", + "y2045_TotCap_CE = d_vars['vCENewCap'][d_vars['vCENewCap'].sYear=='y2045']\n", + "y2050_TotCap_CE = d_vars['vCENewCap'][d_vars['vCENewCap'].sYear=='y2050']\n", + "\n", + "# Avoid all the variables in sCE that begin with sPE2TE and sTE2TE\n", + "y2020_TotCap_CE = y2020_TotCap_CE[~y2020_TotCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2025_TotCap_CE = y2025_TotCap_CE[~y2025_TotCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2030_TotCap_CE = y2030_TotCap_CE[~y2030_TotCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2035_TotCap_CE = y2035_TotCap_CE[~y2035_TotCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2040_TotCap_CE = y2040_TotCap_CE[~y2040_TotCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2045_TotCap_CE = y2045_TotCap_CE[~y2045_TotCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2050_TotCap_CE = y2050_TotCap_CE[~y2050_TotCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2020_TotCap_CE = y2020_TotCap_CE[~y2020_TotCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2025_TotCap_CE = y2025_TotCap_CE[~y2025_TotCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2030_TotCap_CE = y2030_TotCap_CE[~y2030_TotCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2035_TotCap_CE = y2035_TotCap_CE[~y2035_TotCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2040_TotCap_CE = y2040_TotCap_CE[~y2040_TotCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2045_TotCap_CE = y2045_TotCap_CE[~y2045_TotCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2050_TotCap_CE = y2050_TotCap_CE[~y2050_TotCap_CE.sCE.str.startswith('sTE2TE')]\n", + "\n", + "# Delete the column sYear and make the index the column sCE\n", + "y2020_TotCap_CE = y2020_TotCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2025_TotCap_CE = y2025_TotCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2030_TotCap_CE = y2030_TotCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2035_TotCap_CE = y2035_TotCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2040_TotCap_CE = y2040_TotCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2045_TotCap_CE = y2045_TotCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2050_TotCap_CE = y2050_TotCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "\n", + "#graph the results in a bar chart for each technology\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "# Create a figure and a set of subplots\n", + "fig, ax = plt.subplots(1, 1, figsize=(10, 5))\n", + "\n", + "# Set the bar width\n", + "barWidth = 0.15\n", + "\n", + "# Set the position of the bars on the x-axis\n", + "r1 = np.arange(len(y2020_TotCap_CE))\n", + "r2 = [x + barWidth for x in r1]\n", + "r3 = [x + barWidth for x in r2]\n", + "r4 = [x + barWidth for x in r3]\n", + "r5 = [x + barWidth for x in r4]\n", + "r6 = [x + barWidth for x in r5]\n", + "r7 = [x + barWidth for x in r6]\n", + "r8 = [x + barWidth for x in r7]\n", + "r9 = [x + barWidth for x in r8]\n", + "\n", + "# Make the plot\n", + "plt.bar(r1, y2020_TotCap_CE.vCENewCap, color='b', width=barWidth, label='2020')\n", + "plt.bar(r2, y2025_TotCap_CE.vCENewCap, color='r', width=barWidth, label='2025')\n", + "plt.bar(r3, y2030_TotCap_CE.vCENewCap, color='g', width=barWidth, label='2030')\n", + "plt.bar(r4, y2035_TotCap_CE.vCENewCap, color='y', width=barWidth, label='2035')\n", + "plt.bar(r5, y2040_TotCap_CE.vCENewCap, color='c', width=barWidth, label='2040')\n", + "plt.bar(r6, y2045_TotCap_CE.vCENewCap, color='m', width=barWidth, label='2045')\n", + "plt.bar(r7, y2050_TotCap_CE.vCENewCap, color='k', width=barWidth, label='2050')\n", + "\n", + "# Add xticks on the middle of the group bars\n", + "plt.xlabel('Technologies', fontweight='bold')\n", + "plt.xticks([r + barWidth for r in range(len(y2020_TotCap_CE))], y2020_TotCap_CE.index, rotation=90)\n", + "plt.ylabel('Capacity [GW]')\n", + "plt.title('New Capacity by Year and Technology')\n", + "# Create legend & Show graphic\n", + "plt.legend()\n", + "plt.show()" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 18, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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RESEEEKI33//XTRt2lRUrVpVOt/btm0TQggxYMAAYWNjI3JycjSOce7cuUKlUonr168Xex7kHl9qaqowMjIS48aNKxSjfv36olOnTs8950ePHhVqtVp8+eWXYtGiRQKACAsLE0IIcfbsWWFmZibq168v5syZI5YtWyY6dOggVCqV2Lp1qxTjzz//FDVr1hQTJ04U3333nQgMDBTVqlUTZmZm4tatW9J2+eevfv36omnTpmLBggVi9uzZIj09vdj8HBwcxKeffiqWLVsmFixYIFq1aiUAiN27d2tsB0A0adJE2NnZiRkzZohFixaJGjVqiEqVKol79+5J2505c0YYGRkJJycnMXv2bDFjxgxhY2MjGjduLJR+LWjQoIHo2LGjdD89PV00btxYWFpaii+//FIEBQWJQYMGCZVKJcaMGaPx2CFDhggAolu3bmLRokVi/vz5olevXmLp0qWKj2natGkCgGjWrJno3bu3WLFihfjoo48EADFhwgSN/Q4ePFgAEH369BHLly8XgwYNEgCEt7e3xnYdO3bUOLZHjx4JV1dXoaenJ/z9/cWSJUtE+/btBQCxaNEiabvc3Fzh5uYmdHR0hJ+fn1i2bJl46623RJMmTQQAERwcLITQznOXiMoWCykiKnMnTpwQAMS+ffuEEELk5eUJBweHQl+8pk6dKgBofIHNl18Q/PnnnxpfVgp6upDau3evACB27dqlsV337t1FjRo1pPs//fSTUKvV4o8//tDYLigoSAAQhw8fLvbYduzYIQCIhQsXFrtNQTk5OYUKuwcPHggbGxuNYiy/0DAyMhL//vuvtPzYsWMCgPD395eWPXr0qNB+fv75ZwFAHDx4UFo2aNAgoVarpQKyoPzz+3QhJYQQPXr00Div+fLP72+//aaxvHHjxhpfUIui5Pj69+8v7O3tRW5urrTs5MmTxT4PiuLn5yf09PSEsbGx6N+/v7S8c+fOolGjRiIjI0NalpeXJ9q2bStq164tLcvIyNDYf/4xGBgYiMDAQGlZ/vmrUaNGkf8vRXl6u6ysLNGwYcNCX7QBCH19fXHlyhVp2enTpwUAjeLE29tbGBoaahSy58+fFzo6Oi9cSM2YMUNUrlxZXLp0SWO7iRMnCh0dHXHjxg0hhBDh4eECgPjss88KxSxY3Ms9pvxC6ukfLN59911haWkp3T916pQAID766CON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bUtlP4GBgThy5AjatWunaGp1otLSqVMnfPvtt9i9ezcyMjJQq1YtLF26tNAkGnzuElVsHCNFRERERESkEMdIERERERERKcRCioiIiIiISCGOkcKTK47Hx8fDxMSkyAvlERERERHR60EIgYcPH8Le3h5qdfHtTiykAMTHx8PR0bGs0yAiIiIionLi5s2bcHBwKHY9CykAJiYmAJ6cLFNT0zLOhoiIiIiIykpqaiocHR2lGqE4LKQAqTufqakpCykiIiIiInrukB9ONkFERERERKQQCykiIiIiIiKFWEgREREREREpxDFSREREREQVQG5uLrKzs8s6jQpPR0cHurq6L3zZIxZSRERERETlXFpaGv79918IIco6lVdCpUqVYGdnB319/RLHYCFFRERERFSO5ebm4t9//0WlSpVgZWX1wi0przMhBLKysnD37l3ExcWhdu3az7zo7rOwkCIiIiIiKseys7MhhICVlRWMjIzKOp0Kz8jICHp6erh+/TqysrJgaGhYojicbIKIiIiIqAJgS5T2lLQVSiOGFvIgIiIiIiJ6rbCQIiIiIiIiUohjpIiIiIiIKqCX3dOPEwZqYosUERERERFp3ezZs9GyZUuYmJjA2toa3t7eiI2N1dgmIyMDvr6+sLS0hLGxMXx8fJCYmCitP336NPr37w9HR0cYGRnB1dUVixcvLrSvyMhING/eHAYGBqhVqxZCQkJK+/BYSBERERERkfZFRUXB19cXR48exb59+5CdnY0uXbogPT1d2sbf3x+7du3Cpk2bEBUVhfj4ePTu3VtaHxMTA2tra6xbtw7nzp3DV199hUmTJmHZsmXSNnFxcejRowc8PDxw6tQpjB07Fh999BH27t1bqsenEryqF1JTU2FmZoaUlBSYmpqWdTpERERERJKMjAzExcXBxcVFY6ruita17+7du7C2tkZUVBQ6dOiAlJQUWFlZITQ0FH369AEAXLx4Ea6uroiOjkabNm2KjOPr64sLFy4gPDwcAPDFF19gz549OHv2rLRNv379kJycjLCwsCJjFHdOAfm1AVukiIiIiIio1KWkpAAALCwsADxpbcrOzoanp6e0Tb169eDk5ITo6OhnxsmPAQDR0dEaMQDAy8vrmTG0gZNNEBFRkQper6S8dV4oz7kREVFheXl5GDt2LNq1a4eGDRsCABISEqCvrw9zc3ONbW1sbJCQkFBknCNHjuCXX37Bnj17pGUJCQmwsbEpFCM1NRWPHz8utYsYs5AiIiIiIqJS5evri7Nnz+LQoUMljnH27Fn06tUL06ZNQ5cuXbSYXcmwax8REREREZUaPz8/7N69GxEREXBwcJCW29raIisrC8nJyRrbJyYmwtbWVmPZ+fPn0blzZ4wYMQKTJ0/WWGdra6sx019+DFNT01JrjQJYSBERERERUSkQQsDPzw/btm1DeHg4XFxcNNa3aNECenp6OHDggLQsNjYWN27cgJubm7Ts3Llz8PDwwODBgzFz5sxC+3Fzc9OIAQD79u3TiFEa2LWPiIiIiIi0ztfXF6GhodixYwdMTEykcU9mZmYwMjKCmZkZhg8fjoCAAFhYWMDU1BSjR4+Gm5ubNGPf2bNn0alTJ3h5eSEgIECKoaOjAysrKwDAyJEjsWzZMkyYMAHDhg1DeHg4Nm7cqDGOqjSwkCIiIiIiqoDK+1w7K1euBAC4u7trLA8ODsaQIUMAAAsXLoRarYaPjw8yMzPh5eWFFStWSNtu3rwZd+/exbp167Bu3TppubOzM65duwYAcHFxwZ49e+Dv74/FixfDwcEBq1atgpeXV6keH68jBV5HioioKOV5ZrzynBsRkbY965pHVDK8jhQREREREVEZYCFFRERERESkEAspIiIiIiIihVhIERERERERKcRCioiIiIiISCEWUkRERERERAqxkCIiIiIiIlKIhRQREREREZFCLKSIiIiIiIgU0i3rBIiIiIiIqARUqpe7PyFe7v7KObZIERERERGR1s2ePRstW7aEiYkJrK2t4e3tjdjYWI1tMjIy4OvrC0tLSxgbG8PHxweJiYnS+tOnT6N///5wdHSEkZERXF1dsXjxYo0YkZGRUKlUhW4JCQmlenwspIiIiIiISOuioqLg6+uLo0ePYt++fcjOzkaXLl2Qnp4ubePv749du3Zh06ZNiIqKQnx8PHr37i2tj4mJgbW1NdatW4dz587hq6++wqRJk7Bs2bJC+4uNjcXt27elm7W1daken0oIttGlpqbCzMwMKSkpMDU1Let0iIjKBVWBLiPl7aOiPOdGRKRtGRkZiIuLg4uLCwwNDf9bUcG69t29exfW1taIiopChw4dkJKSAisrK4SGhqJPnz4AgIsXL8LV1RXR0dFo06ZNkXF8fX1x4cIFhIeHA3jSIuXh4YEHDx7A3NxcVi7FnlPIrw3YIkVERERERKUuJSUFAGBhYQHgSWtTdnY2PD09pW3q1asHJycnREdHPzNOfoyCmjZtCjs7O7z11ls4fPiwlrMvrEwLqYMHD+Ltt9+Gvb09VCoVtm/fXuy2I0eOhEqlwqJFizSWJyUlYcCAATA1NYW5uTmGDx+OtLS00k2ciIiIiIhky8vLw9ixY9GuXTs0bNgQAJCQkAB9ff1CrUg2NjbFjm86cuQIfvnlF4wYMUJaZmdnh6CgIGzZsgVbtmyBo6Mj3N3dcfLkyVI7HqCMZ+1LT09HkyZNMGzYMI2+kE/btm0bjh49Cnt7+0LrBgwYgNu3b0v9LocOHYoRI0YgNDS0NFMnIiIiIiKZfH19cfbsWRw6dKjEMc6ePYtevXph2rRp6NKli7S8bt26qFu3rnS/bdu2uHr1KhYuXIiffvrphfJ+ljItpLp164Zu3bo9c5tbt25h9OjR2Lt3L3r06KGx7sKFCwgLC8Off/6JN954AwCwdOlSdO/eHfPnzy+y8AKAzMxMZGZmSvdTU1Nf8EiIiIiIiKgofn5+2L17Nw4ePAgHBwdpua2tLbKyspCcnKzRKpWYmAhbW1uNGOfPn0fnzp0xYsQITJ48+bn7bNWq1QsVbXKU6zFSeXl5GDhwIMaPH48GDRoUWh8dHQ1zc3OpiAIAT09PqNVqHDt2rNi4s2fPhpmZmXRzdHQslfyJiIiIiF5XQgj4+flh27ZtCA8Ph4uLi8b6Fi1aQE9PDwcOHJCWxcbG4saNG3Bzc5OWnTt3Dh4eHhg8eDBmzpwpa9+nTp2CnZ2ddg6kGOX6grxz5syBrq4uPvvssyLXJyQkFJrWUFdXFxYWFs+cN37SpEkICAiQ7qemprKYIiIiIiLSIl9fX4SGhmLHjh0wMTGRvp+bmZnByMgIZmZmGD58OAICAmBhYQFTU1OMHj0abm5u0ox9Z8+eRadOneDl5YWAgAApho6ODqysrAAAixYtgouLCxo0aICMjAysWrUK4eHh+P3330v1+MptIRUTE4PFixfj5MmTGtPcaoOBgQEMDAy0GpOIiIiI6KUq55d/WLlyJQDA3d1dY3lwcDCGDBkCAFi4cCHUajV8fHyQmZkJLy8vrFixQtp28+bNuHv3LtatW4d169ZJy52dnXHt2jUAQFZWFsaNG4dbt26hUqVKaNy4Mfbv3w8PD49SPb5ycx0plUqFbdu2wdvbG8CTyjIgIABq9X+9D3Nzc6FWq+Ho6Ihr165hzZo1GDduHB48eCBtk5OTA0NDQ2zatAnvvvuurH3zOlJERIWV52s1lefciIi07VnXPKKS0cZ1pMpti9TAgQM15pQHAC8vLwwcOBBDhw4FALi5uSE5ORkxMTFo0aIFACA8PBx5eXlo3br1S8+ZiIiIiIheD2VaSKWlpeHKlSvS/bi4OJw6dQoWFhZwcnKCpaWlxvZ6enqwtbWVpjd0dXVF165d8fHHHyMoKAjZ2dnw8/NDv379ip2xj4iIiIiI6EWVaSF14sQJjb6L+RNADB48GCEhIbJirF+/Hn5+fujcubPUv3LJkiWlkS4REZWhSFVkWadAREQkKdNCyt3dXVHf9vwBZQVZWFjw4rtERERERPRSlevrSBEREREREZVHLKSIiIiIiIgUYiFFRERERESkEAspIiIiIiIihVhIERERERERKVRuL8hLRERERETFU01XvdT9iWnyZ9t+HbBFioiIiIiItG727Nlo2bIlTExMYG1tDW9vb8TGxmpsk5GRAV9fX1haWsLY2Bg+Pj5ITEyU1t+/fx9du3aFvb09DAwM4OjoCD8/P6SmpmrEiYyMRPPmzWFgYIBatWrJvibti2AhRUREREREWhcVFQVfX18cPXoU+/btQ3Z2Nrp06YL09HRpG39/f+zatQubNm1CVFQU4uPj0bt3b2m9Wq1Gr169sHPnTly6dAkhISHYv38/Ro4cKW0TFxeHHj16wMPDA6dOncLYsWPx0UcfYe/evaV6fCqh5Iq4r6jU1FSYmZkhJSUFpqamZZ0OEVG5oFL912WkPHxURKoipb894CH9XR5yIyIqTRkZGYiLi4OLiwsMDQ2l5RWta9/du3dhbW2NqKgodOjQASkpKbCyskJoaCj69OkDALh48SJcXV0RHR2NNm3aFBlnyZIlmDdvHm7evAkA+OKLL7Bnzx6cPXtW2qZfv35ITk5GWFhYkTGKO6eA/NqALVJERERERFTqUlJSAAAWFhYAgJiYGGRnZ8PT01Papl69enByckJ0dHSRMeLj47F161Z07NhRWhYdHa0RAwC8vLyKjaEtLKSIiIiIiKhU5eXlYezYsWjXrh0aNmwIAEhISIC+vj7Mzc01trWxsUFCQoLGsv79+6NSpUqoVq0aTE1NsWrVKmldQkICbGxsCsVITU3F48ePS+eAwEKKiIiIiIhKma+vL86ePYsNGzaU6PELFy7EyZMnsWPHDly9ehUBAQFazlA5Tn9ORERERESlxs/PD7t378bBgwfh4OAgLbe1tUVWVhaSk5M1WqUSExNha2urEcPW1ha2traoV68eLCws0L59e0yZMgV2dnawtbXVmOkvP4apqSmMjIxK7bjYIkVERERERFonhICfnx+2bduG8PBwuLi4aKxv0aIF9PT0cODAAWlZbGwsbty4ATc3t2Lj5uXlAQAyMzMBAG5ubhoxAGDfvn3PjKENbJEiIiIiIiKt8/X1RWhoKHbs2AETExNp3JOZmRmMjIxgZmaG4cOHIyAgABYWFjA1NcXo0aPh5uYmzdj366+/IjExES1btoSxsTHOnTuH8ePHo127dqhevToAYOTIkVi2bBkmTJiAYcOGITw8HBs3bsSePXtK9fhYSBERERERVUAvOh15aVu5ciUAwN3dXWN5cHAwhgwZAuDJ2Ce1Wg0fHx9kZmbCy8sLK1askLY1MjLCDz/8AH9/f2RmZsLR0RG9e/fGxIkTpW1cXFywZ88e+Pv7Y/HixXBwcMCqVavg5eVVqsfH60iB15EiIioKryNFRFQ+POuaR1QyvI4UERERERFRGWAhRUREREREpBALKSIiIiIiIoVYSBERERERESnEQoqIiIiIiEghFlJEREREREQKsZAiIiIiIiJSiBfkJSIiScFrNREREVHx2CJFRERERESkEFukiIiIiIgqoMhI1Uvdn7u7eKn7K+/YIkVERERERFo3e/ZstGzZEiYmJrC2toa3tzdiY2M1tsnIyICvry8sLS1hbGwMHx8fJCYmSuvv37+Prl27wt7eHgYGBnB0dISfnx9SU1OlbSIjI6FSqQrdEhISSvX4WEgREREREZHWRUVFwdfXF0ePHsW+ffuQnZ2NLl26ID09XdrG398fu3btwqZNmxAVFYX4+Hj07t1bWq9Wq9GrVy/s3LkTly5dQkhICPbv34+RI0cW2l9sbCxu374t3aytrUv1+Ni1j4iIyi1VZKT0d0TZpUFERCUQFhamcT8kJATW1taIiYlBhw4dkJKSgtWrVyM0NBSdOnUCAAQHB8PV1RVHjx5FmzZtUKVKFYwaNUqK4ezsjE8//RTz5s0rtD9ra2uYm5uX6jEVxBYpIiIiIiIqdSkpKQAACwsLAEBMTAyys7Ph6ekpbVOvXj04OTkhOjq6yBjx8fHYunUrOnbsWGhd06ZNYWdnh7feeguHDx8uhSPQxEKKiIiIiIhKVV5eHsaOHYt27dqhYcOGAICEhATo6+sXakWysbEpNL6pf//+qFSpEqpVqwZTU1OsWrVKWmdnZ4egoCBs2bIFW7ZsgaOjI9zd3XHy5MlSPSYWUkREREREVKp8fX1x9uxZbNiwoUSPX7hwIU6ePIkdO3bg6tWrCAgIkNbVrVsXn3zyCVq0aIG2bdtizZo1aNu2LRYuXKit9IvEMVJERERERFRq/Pz8sHv3bhw8eBAODg7ScltbW2RlZSE5OVmjVSoxMRG2trYaMWxtbWFra4t69erBwsIC7du3x5QpU2BnZ1fkPlu1aoVDhw6VyvHkY4sUERERERFpnRACfn5+2LZtG8LDw+Hi4qKxvkWLFtDT08OBAwekZbGxsbhx4wbc3NyKjZuXlwcAyMzMLHabU6dOFVtkaQtbpIiIiIiISOt8fX0RGhqKHTt2wMTERBr3ZGZmBiMjI5iZmWH48OEICAiAhYUFTE1NMXr0aLi5uaFNmzYAgF9//RWJiYlo2bIljI2Nce7cOYwfPx7t2rVD9erVAQCLFi2Ci4sLGjRogIyMDKxatQrh4eH4/fffS/X4WEgREREREVVA7u6irFN4ppUrVwIA3N3dNZYHBwdjyJAhAJ6MfVKr1fDx8UFmZia8vLywYsUKaVsjIyP88MMP8Pf3R2ZmJhwdHdG7d29MnDhR2iYrKwvjxo3DrVu3UKlSJTRu3Bj79++Hh4dHqR6fSghRZv8DBw8exLx58xATE4Pbt29j27Zt8Pb2BgBkZ2dj8uTJ+PXXX/HPP//AzMwMnp6e+N///gd7e3spRlJSEkaPHo1du3ZJ/wmLFy+GsbGx7DxSU1NhZmaGlJQUmJqaavswiYgqjEhVpPS3B/77ACqrjwqN60gV+DwsD7kREb0sGRkZiIuLg4uLCwwNDcs6nVfCs86p3NqgTMdIpaeno0mTJli+fHmhdY8ePcLJkycxZcoUnDx5Elu3bkVsbCzeeecdje0GDBiAc+fOYd++fdIgthEjRrysQyAiIiIiotdQmXbt69atG7p161bkOjMzM+zbt09j2bJly9CqVSvcuHEDTk5OuHDhAsLCwvDnn3/ijTfeAAAsXboU3bt3x/z58zVaroiIiIiIiLSlQs3al5KSApVKJU2PGB0dDXNzc6mIAgBPT0+o1WocO3as2DiZmZlITU3VuBEREREREclVYQqpjIwMfPHFF+jfv7/UVzEhIQHW1tYa2+nq6sLCwqLQ1ZALmj17NszMzKSbo6NjqeZORERERESvlgpRSGVnZ+O9996DEEKa/eNFTJo0CSkpKdLt5s2bWsiSiIiIiIheF+V++vP8Iur69esIDw/XmDnD1tYWd+7c0dg+JycHSUlJha6GXJCBgQEMDAxKLWciIiIiInq1lesWqfwi6vLly9i/fz8sLS011ru5uSE5ORkxMTHSsvDwcOTl5aF169YvO10iIiIiInpNlGmLVFpaGq5cuSLdj4uLw6lTp2BhYQE7Ozv06dMHJ0+exO7du5GbmyuNe7KwsIC+vj5cXV3RtWtXfPzxxwgKCkJ2djb8/PzQr18/zthHRERERESlpkwLqRMnTmhccTggIAAAMHjwYHz99dfYuXMnAKBp06Yaj4uIiJCukLx+/Xr4+fmhc+fO0gV5lyxZ8lLyJyIiIiKi11OZFlLu7u7PvCK9nKvVW1hYIDQ0VJtpERERERGVe6rIyJe6P/H/DRn0RLkeI0VERERERBXT7Nmz0bJlS5iYmMDa2hre3t6IjY3V2CYjIwO+vr6wtLSEsbExfHx8kJiYWGS8+/fvw8HBASqVCsnJyRrrIiMj0bx5cxgYGKBWrVoICQkppaP6DwspIiIiIiLSuqioKPj6+uLo0aPYt28fsrOz0aVLF6Snp0vb+Pv7Y9euXdi0aROioqIQHx+P3r17Fxlv+PDhaNy4caHlcXFx6NGjBzw8PHDq1CmMHTsWH330Efbu3VtqxwZUgOnPiYiIiIio4gkLC9O4HxISAmtra8TExKBDhw5ISUnB6tWrERoaik6dOgEAgoOD4erqiqNHj6JNmzbSY1euXInk5GRMnToVv/32m0bcoKAguLi44NtvvwUAuLq64tChQ1i4cCG8vLxK7fjYIkVERERERKUuJSUFwJM5DgAgJiYG2dnZ8PT0lLapV68enJycEB0dLS07f/48AgMDsXbtWqjVhcuX6OhojRgA4OXlpRGjNLCQIiIiIiKiUpWXl4exY8eiXbt2aNiwIQAgISEB+vr6MDc319jWxsZGuuxRZmYm+vfvj3nz5sHJyanI2AkJCbCxsSkUIzU1FY8fP9b+wfw/du0jIiIiIqJS5evri7Nnz+LQoUOKHjdp0iS4urriww8/LKXMSo4tUkREREREVGr8/Pywe/duREREwMHBQVpua2uLrKysQjPwJSYmwtbWFgAQHh6OTZs2QVdXF7q6uujcuTMAoGrVqpg2bZoU5+mZ/hITE2FqagojI6NSOy62SBERERERkdYJITB69Ghs27YNkZGRcHFx0VjfokUL6Onp4cCBA/Dx8QEAxMbG4saNG3BzcwMAbNmyRaN73p9//olhw4bhjz/+QM2aNQEAbm5u+PXXXzVi79u3T4pRWlhIERERERGR1vn6+iI0NBQ7duyAiYmJNO7JzMwMRkZGMDMzw/DhwxEQEAALCwuYmppi9OjRcHNzk2bsyy+W8t27dw/Ak5n58sdWjRw5EsuWLcOECRMwbNgwhIeHY+PGjdizZ0+pHh8LKSIiIiKiCki4u5d1Cs+0cuVKAID7U3kGBwdjyJAhAICFCxdCrVbDx8cHmZmZ8PLywooVKxTtx8XFBXv27IG/vz8WL14MBwcHrFq1qlSnPgdYSBERERERUSkQQjx3G0NDQyxfvhzLly+XFdPd3b3IuO7u7vjrr78U5/giONkEERERERGRQiykiIiIiIiIFGIhRUREREREpBALKSIiIiIiIoVYSBERERERESnEQoqIiIiIiEghFlJEREREREQKsZAiIiIiIiJSiIUUERERERGRQrplnQARERERESkXqYp8qftzF+4vdX/lHVukiIiIiIhI62bPno2WLVvCxMQE1tbW8Pb2RmxsrMY2GRkZ8PX1haWlJYyNjeHj44PExMQi492/fx8ODg5QqVRITk6WlkdGRkKlUhW6JSQklObhsZAiIiIiIiLti4qKgq+vL44ePYp9+/YhOzsbXbp0QXp6urSNv78/du3ahU2bNiEqKgrx8fHo3bt3kfGGDx+Oxo0bF7u/2NhY3L59W7pZW1tr/ZgKYtc+IiIiIiLSurCwMI37ISEhsLa2RkxMDDp06ICUlBSsXr0aoaGh6NSpEwAgODgYrq6uOHr0KNq0aSM9duXKlUhOTsbUqVPx22+/Fbk/a2trmJubl9rxPI0tUkREREREVOpSUlIAABYWFgCAmJgYZGdnw9PTU9qmXr16cHJyQnR0tLTs/PnzCAwMxNq1a6FWF1++NG3aFHZ2dnjrrbdw+PDhUjqK/7CQIiIiIiKiUpWXl4exY8eiXbt2aNiwIQAgISEB+vr6hVqRbGxspPFNmZmZ6N+/P+bNmwcnJ6ciY9vZ2SEoKAhbtmzBli1b4OjoCHd3d5w8ebJUj4ld+4iIiIiIqFT5+vri7NmzOHTokKLHTZo0Ca6urvjwww+L3aZu3bqoW7eudL9t27a4evUqFi5ciJ9++qnEOT8PW6SIiIiIiKjU+Pn5Yffu3YiIiICDg4O03NbWFllZWRoz8AFAYmIibG1tAQDh4eHYtGkTdHV1oauri86dOwMAqlatimnTphW7z1atWuHKlSvaP5gC2CJFRERERERaJ4TA6NGjsW3bNkRGRsLFxUVjfYsWLaCnp4cDBw7Ax8cHwJOZ927cuAE3NzcAwJYtW/D48WPpMX/++SeGDRuGP/74AzVr1ix236dOnYKdnV0pHNV/WEgREREREZHW+fr6IjQ0FDt27ICJiYk07snMzAxGRkYwMzPD8OHDERAQAAsLC5iammL06NFwc3OTZux7uli6d+8eAMDV1VUaW7Vo0SK4uLigQYMGyMjIwKpVqxAeHo7ff/+9VI+PhRQRERERUQXkLtzLOoVnWrlyJQDA3d1dY3lwcDCGDBkCAFi4cCHUajV8fHyQmZkJLy8vrFixQtF+srKyMG7cONy6dQuVKlVC48aNsX//fnh4eGjjMIqlEkKIUt1DBZCamgozMzOkpKTA1NS0rNMhInqpVJGR0t8RBT5zPPDfnbL6qCjPuRERvSwZGRmIi4uDi4sLDA0NyzqdV8Kzzqnc2oCTTRARERERESnEQoqIiIiIiEghFlJEREREREQKsZAiIiIiIiJSiIUUERERERGRQiykiIiIiIiIFCrTQurgwYN4++23YW9vD5VKhe3bt2usF0Jg6tSpsLOzg5GRETw9PXH58mWNbZKSkjBgwACYmprC3Nwcw4cPR1pa2ks8CiIiIiIiet2UaSGVnp6OJk2aYPny5UWunzt3LpYsWYKgoCAcO3YMlStXhpeXFzIyMqRtBgwYgHPnzmHfvn3YvXs3Dh48iBEjRrysQyAiIiIioteQblnuvFu3bujWrVuR64QQWLRoESZPnoxevXoBANauXQsbGxts374d/fr1w4ULFxAWFoY///wTb7zxBgBg6dKl6N69O+bPnw97e/uXdixERERERPT6KLdjpOLi4pCQkABPT09pmZmZGVq3bo3o6GgAQHR0NMzNzaUiCgA8PT2hVqtx7NixYmNnZmYiNTVV40ZEREREVJGoVKqXelNq9uzZaNmyJUxMTGBtbQ1vb2/ExsZqbJORkQFfX19YWlrC2NgYPj4+SExMfO5xbtiwQWObyMhING/eHAYGBqhVqxZCQkIU56tUuS2kEhISAAA2NjYay21sbKR1CQkJsLa21livq6sLCwsLaZuizJ49G2ZmZtLN0dFRy9kTEREREb3eoqKi4Ovri6NHj2Lfvn3Izs5Gly5dkJ6eLm3j7++PXbt2YdOmTYiKikJ8fDx69+5dKFZwcDBu374t3by9vaV1cXFx6NGjBzw8PHDq1CmMHTsWH330Efbu3Vuqx1emXfvKyqRJkxAQECDdT01NZTFFRERERKRFYWFhGvdDQkJgbW2NmJgYdOjQASkpKVi9ejVCQ0PRqVMnAE8KJldXVxw9ehRt2rSRHmtubg5bW9si9xMUFAQXFxd8++23AABXV1ccOnQICxcuhJeXVykdXTlukco/UU837SUmJkrrbG1tcefOHY31OTk5SEpKKvZEA4CBgQFMTU01bkREREREVHpSUlIAABYWFgCAmJgYZGdnawzlqVevHpycnKShPPl8fX1RtWpVtGrVCmvWrIEQQloXHR2tEQMAvLy8CsXQtnJbSLm4uMDW1hYHDhyQlqWmpuLYsWNwc3MDALi5uSE5ORkxMTHSNuHh4cjLy0Pr1q1fes5ERERERFRYXl4exo4di3bt2qFhw4YAngzT0dfXh7m5uca2BYfyAEBgYCA2btyIffv2wcfHB59++imWLl0qrU9ISChyOFBqaioeP35casckq2tf8+bNFQVVqVTYuXMnqlWr9szt0tLScOXKFel+XFwcTp06BQsLCzg5OWHs2LH45ptvULt2bbi4uGDKlCmwt7eX+kS6urqia9eu+PjjjxEUFITs7Gz4+fmhX79+nLGPiIiIiKic8PX1xdmzZ3Ho0CHFj50yZYr0d7NmzZCeno558+bhs88+02aKiskqpE6dOoVx48bB2Nj4udsKIfC///0PmZmZz932xIkT8PDwkO7nj1saPHgwQkJCMGHCBKSnp2PEiBFITk7Gm2++ibCwMBgaGkqPWb9+Pfz8/NC5c2eo1Wr4+PhgyZIlcg6LiIiIiIhKmZ+fn3S9VwcHB2m5ra0tsrKykJycrNEqVXAoT1Fat26NGTNmIDMzEwYGBrC1tS1yOJCpqSmMjIy0fjz5ZE82MX78+EIz5BUnf6DX87i7u2v0b3yaSqVCYGAgAgMDi93GwsICoaGhsvZHREREREQvhxACo0ePxrZt2xAZGQkXFxeN9S1atICenh4OHDgAHx8fAEBsbCxu3LghDeUpyqlTp1ClShUYGBgAeDLc59dff9XYZt++fc+MoQ2yCqm4uDhUrVpVdtDz58+zax0RERER0WvM19cXoaGh2LFjB0xMTKRxT2ZmZjAyMoKZmRmGDx+OgIAAWFhYwNTUFKNHj4abm5s0Y9+uXbuQmJiINm3awNDQEPv27cOsWbPw+eefS/sZOXIkli1bhgkTJmDYsGEIDw/Hxo0bsWfPnlI9PlmFlLOzs6KgnEqciIiIiOj1tnLlSgBPeqEVFBwcjCFDhgAAFi5cKA3PyczMhJeXF1asWCFtq6enh+XLl8Pf3x9CCNSqVQsLFizAxx9/LG3j4uKCPXv2wN/fH4sXL4aDgwNWrVpVqlOfAwq69jk7O6NTp07w8PCAh4cHiyUiIiIiojL0rCEy5YGc/AwNDbF8+XIsX768yPVdu3ZF165dnxvH3d0df/31l+IcX4TsQmro0KGIjIzEhg0bkJWVBRcXF3h4eEjF1bMGhBEREREREb1KZBdSX3/9NQAgMzMThw8fRlRUFCIjI/HTTz8hOzsbderUQadOnYqtJomIiIiIiF4Vii/Ia2BggE6dOmH69OmIiorC7du3MWnSJMTHxyMoKKg0ciQiIiIiIipXZLdI5cvKykJ0dDQiIyMRGRmJY8eOoVq1aujTpw86duxYGjkSERERERGVK7ILqcDAQKlwcnZ2RocOHTBixAisX7+eU50TEREREdFrRdEYKScnJ3z77bfo27cvLC0tSzMvIiIiIiIqoLzP0leR5OXlvXAM2YXUb7/9hoiICISEhGDMmDGoU6cO3N3d0bFjR3Ts2BFWVlYvnAwREREREWnS09ODSqXC3bt3YWVlBZVKVdYpVVhCCGRlZeHu3btQq9XQ19cvcSzZhZSXl5d0UauHDx/ijz/+QFRUFObOnYsBAwagVq1a8PDwwLJly0qcDBERERERadLR0YGDgwP+/fdfXLt2razTeSVUqlQJTk5OUKsVz70nUYkXaCPMzc3F8ePHsXPnTqxYsQJpaWnIzc0tcTJlJTU1FWZmZkhJSYGpqWlZp0NE9FKpIiOlvyM8/lvugf/ulFV3kvKcGxHRy5abm4vs7OyyTqPC09HRga6ubrEte3JrA0Wz9uXl5eHEiROIiIhAZGQkDh8+jPT0dDg4OODdd9+Fh4fH84MQEREREZFiOjo60NHRKes06P/JLqS6deuGI0eO4OHDh7C3t4eHhwcWLlwIDw8P1KhRozRzJCIiIiIiKldkF1Lm5uaYN28ePDw8ULt27dLMiYiIiIiIqFyTXUj9/PPPpZkHERERERFRhSG7kMrIyMD+/fvRs2dPAMCkSZOQmZkprdfR0cGMGTNgaGio/SyJiIiIiIjKEdmFVEhICPbs2SMVUsuWLUODBg1gZGQEALh48SLs7e3h7+9fOpkSERERERGVE7InTl+/fj1GjBihsSw0NBQRERGIiIjAvHnzsHHjRq0nSEREREREVN7ILqSuXLmCRo0aSfcNDQ01LmDVqlUrnD9/XrvZERERERERlUOyu/YlJydrjIm6e/euxvq8vDyN9URERERERK8q2S1SDg4OOHv2bLHrz5w5AwcHB60kRUREREREVJ7JLqS6d++OqVOnIiMjo9C6x48fY/r06ejRo4dWkyMiIiIiIiqPZHft+/LLL7Fx40bUrVsXfn5+qFOnDgAgNjYWy5YtQ05ODr788stSS5SIiIiIiKi8kF1I2djY4MiRIxg1ahQmTpwIIQQAQKVS4a233sKKFStgY2NTaokSERERERGVF7ILKQBwcXFBWFgYkpKScOXKFQBArVq1YGFhUSrJERERERERlUeKCql8FhYWaNWqlbZzISIiIiIiqhBkTTbRu3dvpKamyg46YMAA3Llzp8RJERERERERlWeyWqR27NhR6LpRxRFCYNeuXZgxYwasra1fKDkiIiIiIqLySFYhJYSQZukjIiIiIiJ63ckqpCIiIhQHrlatmuLHEBERERERVQSyCqmOHTuWdh5EREREREQVhqzJJoiIiIiIiOg/LKSIiIiIiIgUYiFFRERERESkEAspIiIiIiIihRQXUtOmTcP169dLIxciIiIiIqIKQXEhtWPHDtSsWROdO3dGaGgoMjMzSyMvIiIiIiKicktxIXXq1Cn8+eefaNCgAcaMGQNbW1uMGjUKf/75p9aTy83NxZQpU+Di4gIjIyPUrFkTM2bMgBBC2kYIgalTp8LOzg5GRkbw9PTE5cuXtZ4LEdGrJDJSJd2IiIhIuRKNkWrWrBmWLFmC+Ph4rF69Gv/++y/atWuHxo0bY/HixUhJSdFKcnPmzMHKlSuxbNkyXLhwAXPmzMHcuXOxdOlSaZu5c+diyZIlCAoKwrFjx1C5cmV4eXkhIyNDKzkQERERERE97YUmmxBCIDs7G1lZWRBCoEqVKli2bBkcHR3xyy+/vHByR44cQa9evdCjRw9Ur14dffr0QZcuXXD8+HFp/4sWLcLkyZPRq1cvNG7cGGvXrkV8fDy2b9/+wvsnIiIiIiIqSokKqZiYGPj5+cHOzg7+/v5o1qwZLly4gKioKFy+fBkzZ87EZ5999sLJtW3bFgcOHMClS5cAAKdPn8ahQ4fQrVs3AEBcXBwSEhLg6ekpPcbMzAytW7dGdHR0sXEzMzORmpqqcSMiIiIiIpJLV+kDGjVqhIsXL6JLly5YvXo13n77bejo6Ghs079/f4wZM+aFk5s4cSJSU1NRr1496OjoIDc3FzNnzsSAAQMAAAkJCQAAGxsbjcfZ2NhI64oye/ZsTJ8+/YXzIyIiIiKi15PiQuq9997DsGHDUK1atWK3qVq1KvLy8l4oMQDYuHEj1q9fj9DQUDRo0ACnTp3C2LFjYW9vj8GDB5c47qRJkxAQECDdT01NhaOj4wvnS0RERERErwfFXfvyx0I97fHjxwgMDNRKUvnGjx+PiRMnol+/fmjUqBEGDhwIf39/zJ49GwBga2sLAEhMTNR4XGJiorSuKAYGBjA1NdW4ERERERERyaW4kJo+fTrS0tIKLX/06JHWu8s9evQIarVmijo6OlJrl4uLC2xtbXHgwAFpfWpqKo4dOwY3Nzet5kJERERERJRPcdc+IQRUqsLXHTl9+jQsLCy0klS+t99+GzNnzoSTkxMaNGiAv/76CwsWLMCwYcMAACqVCmPHjsU333yD2rVrw8XFBVOmTIG9vT28vb21mgsREREREVE+2YVUlSpVoFKpoFKpUKdOHY1iKjc3F2lpaRg5cqRWk1u6dCmmTJmCTz/9FHfu3IG9vT0++eQTTJ06VdpmwoQJSE9Px4gRI5CcnIw333wTYWFhMDQ01GouRERERERE+VRCCCFnwx9//BFCCAwbNgyLFi2CmZmZtE5fXx/Vq1evsN3pUlNTYWZmhpSUFI6XIqLXQmTkfz+GeSBC+jvCAwWW/3dH5keF1qkiI6W/y1tuRET0apJbG8hukcqfJc/FxQVt27aFnp7ei2dJRERERERUAckqpFJTU6VqrFmzZnj8+DEeP35c5LZs0SEiohdRsLUMBVrLiIiIyhNZhVSVKlVw+/ZtWFtbw9zcvMjJJvInocjNzdV6kkREREREROWJrEIqPDxcmpEvPDy8yEKKiIiIiIjodSGrkOrYsaP0t7u7e2nlQkREREREVCEoviBvcHAwNm3aVGj5pk2b8OOPP2olKSIiIiIiovJMcSE1e/ZsVK1atdBya2trzJo1SytJERERERERlWeKC6kbN27AxcWl0HJnZ2fcuHFDK0kRERERERGVZ4oLKWtra5w5c6bQ8tOnT8PS0lIrSREREREREZVnigup/v3747PPPkNERARyc3ORm5uL8PBwjBkzBv369SuNHImIiIiIiMoVWbP2FTRjxgxcu3YNnTt3hq7uk4fn5eVh0KBBHCNFRERERESvBcWFlL6+Pn755RfMmDEDp0+fhpGRERo1agRnZ+fSyI+IiIiIiKjcUVxI5atTpw7q1KmjzVyIiIiIiIgqhBIVUv/++y927tyJGzduICsrS2PdggULtJIYERERERFReaW4kDpw4ADeeecd1KhRAxcvXkTDhg1x7do1CCHQvHnz0siRiIiIiIioXFE8a9+kSZPw+eef4++//4ahoSG2bNmCmzdvomPHjujbt29p5EhERERERFSuKC6kLly4gEGDBgEAdHV18fjxYxgbGyMwMBBz5szReoJERERERETljeKufZUrV5bGRdnZ2eHq1ato0KABAODevXvazY6IiF4Lqukq6e+IjmWYCBERkUyKC6k2bdrg0KFDcHV1Rffu3TFu3Dj8/fff2Lp1K9q0aVMaORIREREREZUrigupBQsWIC0tDQAwffp0pKWl4ZdffkHt2rU5Yx8REREREb0WFBdSNWrUkP6uXLkygoKCtJoQERERERFReVfiC/KeOHECFy5cAADUr18fLVq00FpSRERERERE5ZniQurff/9F//79cfjwYZibmwMAkpOT0bZtW2zYsAEODg7azpGIiIiIiKhcUTz9+UcffYTs7GxcuHABSUlJSEpKwoULF5CXl4ePPvqoNHIkIiIiIiIqVxS3SEVFReHIkSOoW7eutKxu3bpYunQp2rdvr9XkiIiIiIiIyiPFLVKOjo7Izs4utDw3Nxf29vZaSYqIiIiIiKg8U1xIzZs3D6NHj8aJEyekZSdOnMCYMWMwf/58rSZHRERERERUHinu2jdkyBA8evQIrVu3hq7uk4fn5ORAV1cXw4YNw7Bhw6Rtk5KStJcpERERERFROaG4kFq0aFEppEFERERERFRxKC6kBg8eXBp5EBERERERVRglviAvAGRkZCArK0tjmamp6QslREREREREVN4pnmwiPT0dfn5+sLa2RuXKlVGlShWNGxERERER0atOcSE1YcIEhIeHY+XKlTAwMMCqVaswffp02NvbY+3ataWRIxERERERUbmiuGvfrl27sHbtWri7u2Po0KFo3749atWqBWdnZ6xfvx4DBgwojTyJiIiIiIjKDcUtUklJSahRowaAJ+Oh8qc4f/PNN3Hw4EHtZkdERERERFQOKS6katSogbi4OABAvXr1sHHjRgBPWqrMzc21mhwREREREVF5pLiQGjp0KE6fPg0AmDhxIpYvXw5DQ0P4+/tj/PjxWk+QiIiIiIiovFE8Rsrf31/629PTExcvXkRMTAxq1aqFxo0bazU5IiIiIiKi8khxi9TTnJ2d0bt371Irom7duoUPP/wQlpaWMDIyQqNGjXDixAlpvRACU6dOhZ2dHYyMjODp6YnLly+XSi5ERERERESAgkIqPDwc9evXR2pqaqF1KSkpaNCgAf744w+tJvfgwQO0a9cOenp6+O2333D+/Hl8++23Gtermjt3LpYsWYKgoCAcO3YMlStXhpeXFzIyMrSaCxERERERUT7ZXfsWLVqEjz/+GKampoXWmZmZ4ZNPPsGCBQvQvn17rSU3Z84cODo6Ijg4WFrm4uIi/S2EwKJFizB58mT06tULALB27VrY2Nhg+/bt6Nevn9ZyISIiIiIiyie7Rer06dPo2rVrseu7dOmCmJgYrSSVb+fOnXjjjTfQt29fWFtbo1mzZvjhhx+k9XFxcUhISICnp6e0zMzMDK1bt0Z0dHSxcTMzM5GamqpxIyIiIiIikkt2IZWYmAg9Pb1i1+vq6uLu3btaSSrfP//8g5UrV6J27drYu3cvRo0ahc8++ww//vgjACAhIQEAYGNjo/E4GxsbaV1RZs+eDTMzM+nm6Oio1byJiIiIiOjVJruQqlatGs6ePVvs+jNnzsDOzk4rSeXLy8tD8+bNMWvWLDRr1gwjRozAxx9/jKCgoBeKO2nSJKSkpEi3mzdvailjep1ERqqkGxERERG9XmQXUt27d8eUKVOKnMTh8ePHmDZtGnr27KnV5Ozs7FC/fn2NZa6urrhx4wYAwNbWFsCT1rKCEhMTpXVFMTAwgKmpqcaNiOhVp5qukm5ERET0YmQXUpMnT0ZSUhLq1KmDuXPnYseOHdixYwfmzJmDunXrIikpCV999ZVWk2vXrh1iY2M1ll26dAnOzs4Ankw8YWtriwMHDkjrU1NTcezYMbi5uWk1FyIiIiIionyyZ+2zsbHBkSNHMGrUKEyaNAlCCACASqWCl5cXli9fXmis0ovy9/dH27ZtMWvWLLz33ns4fvw4vv/+e3z//ffSvseOHYtvvvkGtWvXhouLC6ZMmQJ7e3t4e3trNRciIiIiIqJ8sgsp4MnFd3/99Vc8ePAAV65cgRACtWvX1riukza1bNkS27Ztw6RJkxAYGAgXFxcsWrQIAwYMkLaZMGEC0tPTMWLECCQnJ+PNN99EWFgYDA0NSyUnIiIiIiIiRYVUvipVqqBly5bazqVIPXv2fObYK5VKhcDAQAQGBr6UfIiIiIiIiGSPkSIiIiIiIqInWEgREREREREpxEKKiIiIiIhIIRZSRERERERECpVosgkiKl2qyEjpb+HuXmZ5EBEREVHR2CJFRERERESkEAspIiIiIiIihVhIERERERERKcRCioiIiIiISCEWUkRERERERAqxkCIiIiIiIlKIhRQREREREZFCLKSIiKjsqFRPbkRERBUMCykiIiIiIiKFWEgREREREREpxEKKiIiIiIhIIRZSRERERERECrGQIiIiIiIiUoiFFBERERERkUIspIiIiIiIiBRiIUVERERERKQQCykiIiIiIiKFWEgREREREREpxEKKiIiIiIhIIRZSRERERERECrGQIiIiIiIiUoiFFBERERERkUIspIiIiIiIiBRiIUVE9CpTqf67ERERkdawkCIiIiIiIlJIt6wTIKInIiMLthhElFkeRERERPR8bJEiIiIiIiJSiIUUERERERGRQiykiIiIiIiIFGIhRUREREREpBALKSIiIiIiIoVYSBERERERESnEQoqIiIiIiEihClVI/e9//4NKpcLYsWOlZRkZGfD19YWlpSWMjY3h4+ODxMTEskuSiIiIiIheeRXmgrx//vknvvvuOzRu3Fhjub+/P/bs2YNNmzbBzMwMfn5+6N27Nw4fPlxGmRIRERERlR7VdJX0d0TH/5Z7IOLJMo//lrkL95eU1eunQrRIpaWlYcCAAfjhhx9QpUoVaXlKSgpWr16NBQsWoFOnTmjRogWCg4Nx5MgRHD16tAwzJiIiIiKiV1mFKKR8fX3Ro0cPeHp6aiyPiYlBdna2xvJ69erByckJ0dHRxcbLzMxEamqqxo2IiIiIiEiucl9IbdiwASdPnsTs2bMLrUtISIC+vj7Mzc01ltvY2CAhIaHYmLNnz4aZmZl0c3R01HbaRERERETao1L9d6NyoVwXUjdv3sSYMWOwfv16GBoaai3upEmTkJKSIt1u3ryptdhE2hapipRuRERERFQ+lOtCKiYmBnfu3EHz5s2hq6sLXV1dREVFYcmSJdDV1YWNjQ2ysrKQnJys8bjExETY2toWG9fAwACmpqYaNyIiIiIiIrnK9ax9nTt3xt9//62xbOjQoahXrx6++OILODo6Qk9PDwcOHICPjw8AIDY2Fjdu3ICbm1tZpExERERERK+Bcl1ImZiYoGHDhhrLKleuDEtLS2n58OHDERAQAAsLC5iammL06NFwc3NDmzZtyiJlIiIiIiJ6DZTrQkqOhQsXQq1Ww8fHB5mZmfDy8sKKFSvKOi0iIiIiInqFVbhCKjIyUuO+oaEhli9fjuXLl5dNQkRERERE9Nop15NNEBERERERlUcspIiIiIiIiBRiIUVERERERKRQhRsjRURERET0OlCp/vtblF0aVAy2SBERERERESnEQoqIiIiIiEghFlJEREREREQKsZAiIiIiIiJSiIUUERERERGRQiykiIiIiIiIFGIhRUREREREpBALKSIiIiIiIoV4QV4iolcML+BIRERU+tgiRUREREREpBBbpIgqEFWBpgYh2NZAREREVFbYIkVERERERKQQCykiOVQqzYEnRERERPRaY9c+IgVU0/8rpiI6lmEiRERERFSm2CJFRERERESkEFukiLRAFRkp/S3c3cssDyIiIiJ6OdgiRUREREREpBALKSIiIiIiIoXYtY+IiF6qghNg8mpoRERUUbFFioiIiIiISCEWUkRERERERAqxkCIiIiIiIlKIY6SIisFxHERERERUHLZIERERERERKcRCioiIiIiISCF27SMiIirHVAX6GQvBjsZEROUFW6SIiIiIiIgUYiFFRERERESkEAspIiIiIiIihVhIERERERERKcRCioiIiIiISCEWUkRERERERAqxkCIiIiIiIlKIhRQREREREZFC5bqQmj17Nlq2bAkTExNYW1vD29sbsbGxGttkZGTA19cXlpaWMDY2ho+PDxITE8soYyIiIiIqTSrVfzeislSuC6moqCj4+vri6NGj2LdvH7Kzs9GlSxekp6dL2/j7+2PXrl3YtGkToqKiEB8fj969e5dh1kRERERE9KrTLesEniUsLEzjfkhICKytrRETE4MOHTogJSUFq1evRmhoKDp16gQACA4OhqurK44ePYo2bdqURdpERERERPSKK9ctUk9LSUkBAFhYWAAAYmJikJ2dDU9PT2mbevXqwcnJCdHR0cXGyczMRGpqqsaNiIiIiIhIrnLdIlVQXl4exo4di3bt2qFhw4YAgISEBOjr68Pc3FxjWxsbGyQkJBQba/bs2Zg+fXpppktEryhVgU75QogyzIReZZGqyLJOgYheEfzcKj0VpkXK19cXZ8+exYYNG1441qRJk5CSkiLdbt68qYUMiYiIiIjodVEhWqT8/Pywe/duHDx4EA4ODtJyW1tbZGVlITk5WaNVKjExEba2tsXGMzAwgIGBQWmmTEREREREr7By3SIlhICfnx+2bduG8PBwuLi4aKxv0aIF9PT0cODAAWlZbGwsbty4ATc3t5edLhERERERvSbKdYuUr68vQkNDsWPHDpiYmEjjnszMzGBkZAQzMzMMHz4cAQEBsLCwgKmpKUaPHg03NzfO2EcVgmr6f/2WIzqWYSL0XByzQkRERAWV60Jq5cqVAAB3d3eN5cHBwRgyZAgAYOHChVCr1fDx8UFmZia8vLywYsWKl5wpEREREb10Ba/Ky4kU6CUr14WUnJlFDA0NsXz5cixfvvwlZERERERERFTOx0gRERERERGVR+W6RYqIqCypIiOlvyPKLg0iIiIqh9giRUREREREpBALKSIiIiIiIoVYSBERERERESnEMVJERAVERhaYSpcjo+gl4pg8IqKKhYUUERERERHJoipw7S45lyp6lbFrHxERERERkUIspIiIiIiIiBRiIUVERERERKQQx0gR0WtPNf2//t4RHcswESIiIqow2CJFRERERESkEFukiEoRZ7YhIiIiejWxkCIiIiIiomJFqiLLOoVyiV37iOi1oVL9d9O8Q0RERKQMCykiIiIiIiKFWEgREREREREpxDFSRET0Uqg0ulFy8hUi0q6Cl7IQ0/geQ6WPhRQREVEZiYwsWFxGlFkeRESkHLv2ERERERERKcQWKSIiIiIi0qCKjJT+Znt50VhIERFRqeG1R4iI6FXFrn1EREREREQKsUWKiKiUFJxIwKNAx4gIDxRY/t8dITjLFBERUUXBFikiIiIiIiKFWEgRVVAq1ZMbEREREb187NpHRERaxZmeiIjodcBCioiIiIiIeJFwhdi1j4iIiIiISCG2SBERvUJU0sA5zgBIRPSyFRy7zIlYX30spIiI6IWxOwgREb1uWEgRaVmkKvLZGxT8ueprLeyQP3+99p77nCMiIiKtYyFVDvF7MZF2qTTmiX81XlScGY+IiKhssZAq71hVEcmmUVx4vIT9/f/LU+C/16nq6//WR3TU7v7YfY6ISJ6C75ceBd4vC342eOC/O6I0vmPxO9wrj4UUEVU4qun/fThpFiuvXnFR/LGWvfKcGxGVL6wpyi++l5ccCykiIiIiKlMFW5Dc3VlpUcXAQoqIyi2NXzCh5Uk6iIioXCrYTVu4u7+cfcrsql3SIq9gq4+YxkLxVcFCqgLhi5Do1VbUBzmLRiJ6nRWcldRduJdZHkRFUZd1AtqyfPlyVK9eHYaGhmjdujWOHz9e1ikRvXSq6SqNgptI61Sq/25ERC+RSqX6/1lY+f7zwvherhWvRCH1yy+/ICAgANOmTcPJkyfRpEkTeHl54c6dO2WdGhEREREVxC/x9Ip4Jbr2LViwAB9//DGGDh0KAAgKCsKePXuwZs0aTJw4sYyzIyKi11FxY/xKc4p8Iir/5EzNzm6MFUOFL6SysrIQExODSZMmScvUajU8PT0RHR1d5GMyMzORmZkp3U9JSQEApKamlm6yJaCRUUaB5eUw11eZdLYL/B+kpxfcIr2Iv56KUdT/2QvEy8+qqOdIWT4/zMz++/v/X1paUdxrQZvnTXk8bcYq37mV+vNX27mVM6X6/0BUwRR8FptNelJU7H6z4BYv+/1SfjzVnj3Sst09/1vfPqV9MRFLlpvmheRTFMd7We/lr+p7Uv5xPe/6YipRKlcge3ni4+NRrVo1HDlyBG5ubtLyCRMmICoqCseOHSv0mK+//hrTp09/mWkSEREREVEFcvPmTTg4OBS7vsK3SJXEpEmTEBAQIN3Py8tDUlISLC0tn/oFoOylpqbC0dERN2/ehKmpabmKx9zKRzzmVvaxmNurGY+5lX0s5lY+4pXn3LQdj7mVfazyQAiBhw8fwt7e/pnbVfhCqmrVqtDR0UFiYqLG8sTERNja2hb5GAMDAxgYGGgsMzc3L60UtcLU1FSrT0xtxmNu5SMecyv7WNqOx9zKRzzmVvaxtB2PuZV9rPIej7mVfayyZlZwrEIxKvysffr6+mjRogUOHDggLcvLy8OBAwc0uvoRERERERFpS4VvkQKAgIAADB48GG+88QZatWqFRYsWIT09XZrFj4iIiIiISJteiULq/fffx927dzF16lQkJCSgadOmCAsLg42NTVmn9sIMDAwwbdq0Ql0Ry0M85lY+4jG3so+l7XjMrXzEY25lH0vb8Zhb2ccq7/GYW9nHqkgq/Kx9REREREREL1uFHyNFRERERET0srGQIiIiIiIiUoiFFBERERERkUIspIiIiIiIiBRiIfWaS0pKKusUiArJzc0t6xSoFBw8eBA5OTllnQYRET0lLS2trFOokFhIvaZ+//13vPfee6hWrVqZ5ZCamoq8vLxCy3Nzc5GamvrC8a9fv47z588XuY8XkZycjGXLlsnaNicnB5mZmRrLEhMTMX36dEyYMAGHDh3Sam4XLlzA559/rtWY2qLkvFWrVg0TJ07EpUuXtLLvvLw8zJkzB+3atUPLli0xceJEPH78WCuxS1tGRgbmz59fJvueOnUqHj16JN1/8ODBC8Xz8PDgjzdUrGHDhuHhw4elFv/cuXM4c+aMdDt37lyp7aus3Lp1C0uWLIGfnx/8/PywdOlS3Lp1S1GM3NxcnDlzpsj3yEePHuHMmTOKPlcfPHiApUuXFvm5npKSUuy6l5GbNmn7c+aff/6BtibWXrhw4TPXP3z4EF5eXlrZ12tHUIWxZcsW0ahRoxI//tq1a2Lq1KnC2dlZmJqaivfff19s3LhR1mMvXbok+vXrJ1JSUgqtS05OFv379xdXr16VncvWrVtF7dq1RXp6eqF1aWlpok6dOmLnzp2yYq1evVp8++23Gss+/vhjoVarhVqtFq6uruLGjRuycyvO/v37Rf/+/YWhoaGwsLCQ9ZghQ4aIESNGSPdTU1OFo6OjsLKyEo0bNxa6urpiz549L5RXWlqaWLVqlXBzcxMqlUo0aNBA1uPu3r0rrl27prHs7NmzYsiQIaJv375i/fr1L5RXvpKct8DAQFGzZk2hVqvFm2++KYKDg4t8rsgVGBgo1Gq16NKli+jVq5cwNDQUQ4cOLXG851H6Wr1z547YtWuX2Lt3r8jJyRFCCJGVlSUWLVokbGxshKWlpexYP/74o6ybHGq1WiQmJkr3TUxMFL3On6ZSqTTiacOlS5fEvHnzhK+vr/Dz8xPffvttiXJs2rSpaNas2XNvcnTr1k0kJydL92fPni0ePHgg3b93755wdXVVlF9aWpqYMmWKaNCggahcubIwNjYWjRo1EtOnT1f02jh9+rSsm1yurq7i/v370v1Ro0aJu3fvSvcTExOFkZGRrFhPP99e1MGDB8Ubb7wh3Tc2NhZqtVqoVCqhUqmEWq0W+/btkx0vPj5efPnll9L9du3aaTw33njjDfHvv//KjpednS3mzp0rmjVrJipXriwqV64smjVrJubNmyeysrJkx8m3fPlyYWBgIFQqlTAzMxNmZmZCpVIJAwMDsXz5ctlxgoODRYsWLaT3oqdzbtGihfjpp59kxwsMDBR9+vQpdn3fvn3FN998Uya5paWliZEjRwp7e3tRtWpV8f7774s7d+7IfnxB2v6cefr18N5774mEhIQSxTI0NCz2fT8tLU20bdtW1K1bV3a86dOny7q9DlhIlTNBQUHCx8dH9O/fXxw9elQIIcSBAwdE06ZNRaVKlcTIkSMVxcvMzBQ///yz6Ny5szA0NBQ9e/YUOjo64syZM4rifPzxx2L8+PHFrp8wYYKi3N566y3xww8/FLt+9erVokuXLrJitW7dWqxZs0a6/9tvvwldXV2xbt06ERMTI9zc3MTw4cNl51bQjRs3xPTp00X16tWFWq0WH3zwgfjtt99kf8jVrl1b7N27V7q/bNkyYW9vL33JmjBhgnB3dy9RbocOHRJDhw4VlStXFmq1WowbN05cuHBB9uP79esnAgICpPuJiYmiSpUqokGDBuKdd94Renp6Yu3atSXK7UXPW76IiAgxaNAgUblyZWFqaio++ugj6XWhRK1atURQUJB0f9++fUJfX1/k5uYqjpVPW6/VP/74Q/rCo1arRatWrcS5c+dE7dq1haurq1i5cqV49OiR7LzMzc2LvVWpUkXo6+sLtVotK9bThY+xsfELF1Il/ZJSlFmzZgldXV2hVquFra2tsLGxEWq1Wujp6Yl58+YpivX1119Lt2nTpgl9fX3x2WefaSz/+uuvZcV6XgGakJAg+/9AiCfv4y1atBAGBgbC29tbTJw4UXzxxRfinXfeEfr6+qJNmzayX1v5z7OCxUT+/YL/yvX0c6SoY1WpVCWK9aL69esnFi9eLN03NjYWUVFR4tq1ayIuLk74+/uL3r17y443efJkMWrUKI14BZ8jrVu3FuPGjZMV69GjR6Jdu3bSF+8xY8aIMWPGiC5dugi1Wi3at28vHj9+LDu33bt3Cx0dHTFu3DgRHx8vLY+Pjxf+/v6KfrR78803xc8//1zs+l9++UW0b99edm5NmjQR+/fvL3b9/v37RdOmTcskN39/f1G5cmUxYsQIMWbMGGFlZSW8vb1lP74gbX/OaPP9d9OmTcLQ0FDs2LFDY3laWppo166dqF27tsbzRk5u1apVE82aNRNNmzYt8ib3h6eKjoVUOTJ79myhp6cnWrRoISpXriwqVaokZs6cKWxtbcXs2bNFUlKSonh+fn7C0tJStGnTRixbtkzcu3dPCCGErq6uOHfunKJYderUEcePHy92/YkTJ0SdOnVkx7OzsxOXL18udv3ly5eFnZ2drFgWFhYaheHIkSOFj4+PdD8iIkJUr15ddm5ZWVli48aNokuXLsLIyEi8++67YtOmTSU6b5UqVRL//POPdP/dd98Vo0ePlu6fO3dOWFlZyY6XmJgo5syZI+rWrStsbW2Fv7+/+PPPP0uUW/Xq1UVkZKR0f968eaJmzZoiOztbut+6dWvZ8bR53p728OFD8cMPP4h27doJlUol6tevX6gV8ln09fULtUoaGBiImzdvligfbb5WO3bsKPr37y/+/vtv8fnnnwuVSiXq1KkjNm3aVKLcihMfHy8++eQToaenJ7y8vGQ9pjQKqe7du4t33333mTc5wsPDhVqtFtOmTdM43/fv3xdTpkwROjo6IioqqsS5vsixPu+8KS2k8lsmL168WGjdhQsXhI2NjViyZImsWNeuXZNucXFxonLlylJxUfAmlzaPVaVSiStXroiUlJRn3uSqVauW+Pvvv4vN7eTJk7I/Z4R40mp58ODBYuOFhYWJ+vXry4o1depU4eTkVGTr36lTp4STk5OYNm2a7Nw6duwovvrqq2LXf/XVV6Jjx46yYllZWYm4uLhi1//zzz+iatWqsnMzNjYW169fL3b99evXhYmJSZnkVr16dY2eOSdOnBC6urrS56AS2v6c0fb77w8//CAqVaokIiIihBBPiqg333xT1KpVS9y6dUtRrO7duwtDQ0PRq1cvsWPHjhf6UbKiYyFVjtSpU0eEhIQIIZ50SVCpVKJHjx4iLS2tRPF0dHTEl19+KVJTUzWWl+SLraGh4TM/XK9duya7+0Z+vGe1npw/f14YGhrKimVkZKSRW+PGjTV+hbx+/brsWEI8eaNu3769+O677zS+oJXkvFlYWGg8xs7OTqxbt066f/XqVcXn7cMPPxRhYWEab1za+D/t1q2bRqtjbGys7K54Qmj3vD3L7t27hYWFhaIvomq1ulBLiLGxsUaRq4Q2X6sFnyOPHj0SarVabN++vUR5FSU1NVV89dVXwtjYWLRu3VqEh4fLfqxarZa+2CYnJwsTExNx+vTpEn+xValU4v333xdDhgx55k2O9957T6Pb7NM+/vhj0a9fP9m5Pa08FVIdOnQQy5YtK3b9kiVLRIcOHUqUqzaKY20WUvktZEXdlLaWGRoaanyx3bJli0Y3yGvXrgl9fX3Z8czNzTW+FL/77rsaXa3i4uJkv5/XqVNHbN68udj1GzduFLVr15adm4mJSZGFdr6LFy/KLlYqVar0zO6dp0+fFpUqVZKdm5mZmYiOji52fXR0tDAzMyuT3HR1dQsVEUZGRs8s/Iqj7c+Zp+O9SKx8c+bMEaampiIiIkK0b99e1KhRo8SF3q1bt8SsWbNEnTp1hK2trZgwYcIzn4OvKt2yHqNF/7lx4wY6deoEAGjfvj309PQwffp0VK5cuUTxfvrpJ6xZswZ2dnbo0aMHBg4ciG7dupUolpmZGa5evQpnZ+ci11+5cgWmpqay41WvXh0nTpxAvXr1ilx/4sSJYvf1NGdnZ8TExMDZ2Rn37t3DuXPn0K5dO2l9QkICzMzMZOeWk5MDlUoFlUoFHR0d2Y8rStOmTfHTTz9h9uzZ+OOPP5CYmCj9HwPA1atXYW9vLzues7MzDh06BCcnJzg7Oxd7/uQwNTVFcnKydJ6PHz+O4cOHS+tVKlWhiTKeRZvn7WmPHj3Cxo0bERwcjEOHDqFmzZoYP3687McLITBkyBAYGBhIyzIyMjBy5EiN19fWrVtlxdPma/XBgweoWrUqAMDIyAiVKlVCw4YNFcd5WnZ2NpYuXYpZs2bB0tISwcHB6NOnj6IYQgjUqVNH436zZs007qtUKkWzLC5ZsgTW1taK8ijK8ePH8dNPPxW7fuDAgRg0aNAL76ck8l8HTy8rqfPnz8Pd3b3Y9R4eHggMDCxx/Beh7WPdvHkzLCwsXjQtAICJiQmuXr0KR0dHAEDv3r011sfFxSn63MrOzsbdu3fh4OAAoPD7xYMHD6BWy5vD6/r162jVqlWx69u0aYMbN27Izi03Nxd6enrFrtfT05P9Oq1duzaOHDmCxo0bF7n+0KFDqF27tuzcmjVrhu3bt6NNmzZFrt+2bZvG+8rLzC0vL6/QedPV1S3RzLHa/px5Ol5RsZTEA4AJEyYgKSkJnTt3RvXq1REZGSk9n5Wyt7fHpEmTMGnSJBw8eBDBwcFo2bIlGjVqhP3798PIyKhEcSsaFlLlSGZmJgwNDaX7+vr6L/SB0r9/f/Tv3x9xcXEICQmBr68vHj16hLy8PJw/fx7169eXHatDhw5YunSpRhFQ0JIlS9C+fXvZ8Xr37o2vvvoKb731FmxsbDTWJSQkYPLkyfjwww9lxRo8eDB8fX1x7tw5hIeHo169emjRooW0/siRI4q+mMbHx2PLli1YvXo1xowZg27duuHDDz8s0ZeDqVOnolu3bti4cSNu376NIUOGwM7OTlq/bds2jaLveS5evIjDhw9j9erVaNmyJerUqSOdJ6X5tWnTBkuWLMEPP/yArVu34uHDhxr/v5cuXZK+gMihzfOW78iRI1izZg02bdqEnJwc9OnTBzNmzECHDh0UxRk8eHChZXKfX0XR9mv1/PnzSEhIAPDkwzM2Nhbp6eka2xT3xeFpQgisXbsWU6dORU5ODmbNmoXhw4eXqLiNiIhQ/JhneZHnwtMSExNRvXr1Yte7uLhI5/Rle94XICU/UABPZry0tLQsdr2lpSVSUlJKnvALEEKgc+fO0NV98nXi8ePHePvtt6Gvrw8Aiqe7b9eunVYKbQBo3bo11q5dW2wRGhISgtatW8uOV7duXRw5cqTYL/1//PGHxg8Pz2Jqaoo7d+4U+x6bkJAAExMT2bk1aNAAO3bsgL+/f5Hrt2/fjgYNGsiK9cEHH2Dy5Mlo27Ztofed06dPY+rUqZgwYYLs3Pz8/NCvXz84ODhg1KhR0ntRbm4uVqxYgYULFyI0NLRMcnv6+Qs8+eGu4HMYAE6ePPncWNr+nHk63ovEevpHBD09PVStWhVjxozRWK6kKCuoZcuWuHbtGs6fP4+//voL2dnZr00hpRJCS3Mr0gtTq9UYMWIEKlWqBABYvnw5Pvzww0KtKQsWLChRfCEEfv/9d6xevRo7d+5E1apV0bt3byxZsuS5j/3rr7/g5uaGnj17YsKECahbty6AJ1/s586diz179uDIkSNo3ry5rFwePnwINzc33LhxAx9++KFGvPXr18PR0RFHjx6V9UGSl5eHr7/+Grt27YKtrS0WLFgAV1dXaX3fvn3RtWtXjdYWua5evYrg4GD8+OOPuHXrFvr3748hQ4agU6dOsr+Ynj9/Hvv27YOtrS369u2r8Yvl999/j1atWqFp06aKc0tLS8PPP/+M4OBgHD16FB07dsQHH3wAb29vWFlZPffxZ86cQefOnZGamoqcnBx8+eWXmDFjhrR+4MCBqFy5MoKCghTn9qLnbe7cuQgODsalS5fwxhtvYPjw4ejfv7+iLxalSZuvVbVaDZVKVeQ0t/nLlbT6NGrUCP/88w9Gjx6NsWPHSjk+Tckv8dqiVquRkJCglS/Kz4uVmJgIe3t72eft6ffBL774AuPHj5daC/N99tlnz401ZMgQWUVjcHCwrNx0dHSQkJBQ7Ota6bEWZGJigjNnzsDFxUXxYwFg+vTpsrabNm3ac7fR5vMDePJDgKenJwICAjB+/Hgp7p07dzBnzhwsXrwYv//+e7E/ED5t3rx5+N///oeIiIgiv8R37txZet48z/vvv4+cnBxs2bKlyPU+Pj7Q0dHBxo0bZeX2448/YtSoUZg/fz5GjBghFQY5OTn47rvvMH78eKxYsQJDhgx5bqzs7Gx06dIFhw4dgqenp9Tz4eLFi9i/fz/atWuHffv2PbMF7GlfffUVZs+eDRMTE9SoUQPAk+m909LSMH78ePzvf/+TFUfbuWnz+VueDR06VNZ2ct+T8kVHR2PNmjXYuHEj6tSpg6FDh+KDDz6Aubl5CbKsmFhIlSPu7u6yPny18StxUlIS1q5di5CQEJw6dUrWY3bv3o1hw4bh/v37GsstLS2xatUqvPPOO4pySElJwaRJk/DLL79I16cxNzdHv379MHPmTFSpUkVRvNKUl5eHvXv3YvXq1di1axeMjY0LnYeydOHCBaxevRo//fQTkpKSkJ2dLetx9+7dw+HDh2Fra1vol9k9e/agfv36Jf6CBZT8vFlZWeHDDz/E8OHDtdLN7VmEEAgLC8Pq1auxefNmWY+R81pVqVQIDw9/bqzr16/L2qfcrq4FC/WiclRSmE2dOhUTJ06UirEHDx680OsyODgYAwcO1Pj1t6TUajW++eYbGBsbF7n+4cOHmDp1quziQs7zXKVS4Z9//lGUpzao1Wo0bNiw2POWk5ODc+fOyTrWZs2aaTwvzpw5g3r16mn8+g7I+wVe21xcXHDixIlntr4ptWLFCvj7+yMnJwempqZQqVRISUmBrq4uvv32W/j5+cmOlZ2dDU9PTxw5cgRvvfWW9ANgbGws9u3bBzc3Nxw4cEDWl/jz58+jdevWaNCgAQICAlCvXj0IIXDhwgUsXLgQ58+fx9GjR2W3IgHA559/jgULFsDExAQ1a9aEEEIqVj777LPnXkvo6WPNbym6fPmy1M33gw8+wNixYws9X+Q4fvw41q9fjytXrmjEe1YXx5eVm7Zcu3YN+/btQ1ZWFtzd3RX9/1Ukc+fORUhICO7du4cBAwZg6NChsntNvGpYSL3GYmJiMG3aNOzevVv2Yx4/foywsDCNN8IuXboU+6u3HEII3Lt3D0IIWFlZKe7+8+DBA6xbtw6DBw8u9Ct7SkoK1q5dW+S6krp37x5WrlyJKVOmPHfbmJgYfP7559ixY0eRuXl7e2PRokVo0qSJVnLLycnBggULFHVteFmUnLfs7GxFv3aWRFxcHNasWYOQkBDcvXsXnp6eil4L5VVUVJSs7Tp27PjcbXR0dHD79m3pl3xTU1OcOnVK+kVZKbVaDWdnZ3h4eEi3kvbPr169uqz3iri4uBLFfxG5ubk4d+4cateuXah7y6NHj3DlyhU0bNhQ9ngabf5qru1f4DMyMvD777/Dw8OjUItxamoqIiMj4eXlpTFuRKmoqCikp6fDzc2tRIX8zZs3sXnzZly+fBnAk3E2ffr0UdR1OV9WVhYWLFiADRs2SBcMr127Nvr37w9/f39Fx3n06FEMHz4cFy5ckJ7LQgjUq1cPq1evhpubm+L8jh49ip9//lk61jp16qBfv37Fjk+iJ+ds165dyMrKQufOndG1a9cSxYmIiEDPnj2li/Dq6upizZo1Je6S93R3vOKUtDteQRcvXsQ777wjPaefR61Ww8nJCT179nxm4VrSHlQVCQupCiS/1WH+/PmyH7N3717s27cP+vr6+Oijj1CjRg1cvHgREydOxK5du+Dl5YVff/21FLMuXv6bV3Z2Njp16lTiN68ZM2bgzJkz2LRpU5Hr33vvPTRp0gRfffXVi6QL4Em/9VmzZmHVqlV49OjRc7f/4IMP4OrqWmzxMHPmTFy4cAHr1q1TlEdaWhp0dHQ0vqSdOnUKU6dOxZ49e2T9Mh0eHg4/Pz8cPXq0yCKvbdu2CAoKUjT2rThKz5uc7qaAvG5WBWVmZmLz5s1YvXo1Dh06hNzcXMyfPx/Dhw9/oUL73r17AFCoG5gSly9fxo4dO3Dt2jWoVCq4uLjA29u7xEWLNjzd1crExASnT58ucU6RkZHS7dixY8jKykKNGjXQqVMnqbB6eszky9KpUyds3bpVK11SQkJCsGzZMhw7dqxQV9acnBy0adMGY8eOfaExDyV148YNODg4yC7inmfx4sXYuXMnDhw4UOR6T09PeHt7y2r5mTNnDtLS0qQuxkIIdOvWDb///jsAwNraGgcOHHjlfuX/66+/NAqfknT11qbBgwejc+fOcHd3h5OTk1ZipqamSu+xv/76q8bYOR0dHfTo0UMr+1Fq8+bNeP/992FkZAQ9PT2kpqZizpw5+PzzzxXHevPNN1G1alWsXLkShoaGmDx5MrZt24b4+PgS5VZa3fGKcvr0aTRv3lx2C742e2VUeKU9LSC9mLS0NLFq1Srh5uYmVCqVaNCggezHrlq1SqhUKmFpaSnUarWwsrISP/30kzA3NxeffPKJOH/+vOxYBw4cEK6urkVOdZycnCzq16+vcX2N59m0aZNQq9WicuXKwtzcXKjVasUX0MynzYv9CSFEUlKS6Nevn7C0tBR2dnZi8eLFIjc3V0yZMkUYGRmJ1q1biw0bNsiKVaNGjWdO1XrmzBnh4uIiO7cbN26INm3aSBcd9ff3F+np6WLgwIFCX19fvP/++7IvWPv222+LBQsWFLt+8eLFii5MqM3zVr169efelJy3EydOiFGjRglzc3PxxhtviMWLF4uEhIQXmpr9wYMH4tNPP5VeX2q1WlhaWgpfX1/x4MEDRbG0eWHZfP/++69YvHix8PX1Fb6+vmLJkiXi33//VRRD29cxKejx48fiwIEDYsqUKaJ9+/bCwMBAqNVq2dfh0TZtXgxW2xcN1aanLxb8olq2bCl27txZ7Ppdu3aJli1byorVrFkzjfeIjRs3CiMjI3Ho0CFx//590aNHD9G3b1/ZuUVFRcm6vQpOnz4t6yZHx44dhaGhoVCr1aJGjRpi+PDhYt26dYou2FrQrl27ND6DjY2NpQtC509pL/e6efkXFn/eTa7mzZuLTz75ROTk5AghnrwXK3l8QWZmZhqfJ+np6UJHR0e6hmd5durUKUWXFqD/sEWqnMqfmW3jxo14/Pgx/P398dFHHyma7rpx48YYOHAgxo8fjy1btqBv375o06YNNm7cqLg7zTvvvAMPD49iZwRasmQJIiIisG3bNlnxWrRogZYtW2L58uXQ0dHB7NmzMW/ePCQlJSnKC3jyK/m5c+eK/eXsxo0baNiwIVJTU2XF++STTxAWFoa+ffti7969OH/+PLy8vKBWqzF58mRFXSQMDQ1x4cKFYsdfxMXFoX79+lJXgOfp168fYmNjMXz4cGzduhVRUVFo3rw5WrdujYkTJyr6f3V2dkZYWJjGxBwFXbx4EV26dJE9Ba82z5u26erqYvTo0Rg5cqQ0rgF4MnPR6dOnFc1gCTwZY+jm5oZbt25hwIAB0jk8f/48QkND4ejoiCNHjsjqhpQ/IH7KlCkYM2aM9JikpCQsWrQIs2bNQnh4uKKZClesWIGAgABkZWVJvwKnpqZCX18fCxYswKeffiorjo6ODi5dugQrKysIIeDo6IhDhw4Vmi3vRVrzsrKycPjwYfz222/47rvvkJaWJutX0bVr18qKL3cKdG1OdGBtbY3jx48XO6tgXFwcWrVqhbt378qK5+HhIevX3+JahQrS9oQOVapUwenTp5/5/tukSRNpHOzzYh05ckR6PQ0dOhS5ubnS//XRo0fRt29f3Lx5U1Zuz2p1yz+fKpVK9syCLi4usv4frl69+txYAQEBsvYpt2vUsyatKZib3BaHzMxMHDlyRKMFOTs7G7Vr14aHhwc6deqEvn37yor1zjvvwNvbG8OGDQNQuGV77ty5iIyMlNU75scff5S1z6Jm0CuKsbExTp06hVq1agF48n5UuXJl3Lp1S/FrpKjX1ou24hfl+vXrSE9PR7169bTWsqy0RYr+w+nPy5E7d+4gJCQEa9asQUpKCvr374/IyEi4ublh2LBhiq8ZdPXqVemNrnfv3tDV1cW8efNKNCbh9OnTmDNnTrHru3TpoqjLYWxsLH755Rep28u4ceMwdepU3LlzR/Gbl46ODuLj44v9II+Pj1f0ZvPbb78hJCQEnTp1gp+fH2rUqIGmTZti1qxZivICnkyaEBsbW2whdfHiRUXdwQ4ePIitW7eiTZs2eO+992Bra4sBAwZg7NixinNLTEx85jgkXV1d2V/0AO2eNzlu3bqFatWqydq2c+fOWL16Ne7cuYOBAwfCy8vrhabiDgwMhL6+Pq5evVqoK1pgYCC6dOmCwMBAWYO7g4KC8NFHH+Hrr7/WWG5hYYHAwEAkJCRg5cqVsgupPXv24LPPPsPYsWMxbtw4abr927dvY968eRgzZgyqV6+O7t27PzeWKIXrSGVlZeHo0aOIiIiQvqA5OjqiQ4cOWLZsmayxWwAKTdtbkEqlQnp6OnJychRdS6rgNPTFkTOgOj09/Zk/3Dx8+FBWF9d8z+rq9fDhQ4SGhiqaUl2b09Dn5OTg7t27xb7/3r17V3ahkpOTozHGKDo6WuO9zd7eXupGK0dxxdujR4+wePFiLFmyRNEX3Ge9z167dg3fffed7P+Hv/7667nbKPl/0vZYQAMDA6m7LfBkLNyRI0fw22+/4fvvv8f3338vu5D6+++/MW/evGLXd+vWTfb3B7kFklyPHj3S+CFIX18fhoaGSEtLK9GPDXv37tWYvTUvLw8HDhzA2bNnpWVyJ+Zas2YNkpOTNYruESNGYPXq1QCeTMe/d+/eEo31e1H169fHoUOHpMt+fPrppwgMDJS+z9y5cwfVq1dX9D5XUbGQKkecnZ3Rp08fLF68GG+99dYL/9Lw+PFjaRIIlUoFAwMDjWsYKaHtL93afPPS5sX+gCeFV/4votWrV4ehoWGJxzJ4enpi5syZRY7/EkJg5syZ8PT0lB0vMTFRKsqsra1RqVKlEl9kuVq1ajh79qz0S9zTzpw5o+j5os3z9iwJCQmYOXMmVq9eLftNeu/evbh58yaCg4MxatQoPH78GO+//z6Akn2p3L59O7777rsix/PY2tpi7ty5GDlypKxCStsXlp03bx4mTpyIb775RmO5nZ0dFixYgEqVKmHu3LmyCiltX0eqU6dOOHbsGFxcXNCxY0d88sknCA0NLdH7UnFfkm/fvo3p06djzZo1eOuttxTF7Ny5s1amodf2RUOLeh7l5ORg+fLlmDlzJqpVq6Zx6YLnmTJlynMnCJLbEtKgQQPs379f49p9Bf3++++yxzTVrFkTBw8eRI0aNXDjxg1cunRJ4weEf//9V9GMfk9fjiAvLw9r1qzB9OnToVarsXz5ckVfzIsq3pOSkjBjxgysXLkSrVu3fuYPjgVp+7Uld1ZPpbKyshAdHY3IyEhERETg2LFjsLe3h4+Pj+wYt2/f1iiQIyIiNL78Gxsbl9l10ABg1apVGrN/5uTkICQkRONHTrnjcYt6Pn3yySfS30p+ePr+++81HhsWFobg4GCsXbsWrq6u8PPzw/Tp07Fq1arnxqpSpcozP+uUXu/t4sWLGo9Zt24dPv/8c+mcCSGQkZGhKGZFxUKqHHF2dsahQ4fg5OQEZ2dnxS1QRSn4BlHUmwMg7w1C21+6n86tuPzk5KbNi/0BT94ACk4z/PSkDkpMnjwZLVq0QOvWrTFu3DiN62V9++23uHTpEkJCQhTFLFhgq9XqEk/12r17d0yZMgVdu3bVuLgs8KQInzZtGnr27Ck7njbP24MHD/Dpp59KE6VMnDgRfn5++PrrrzF//nw0btxY8QBbR0dHTJ06FVOnTsW+ffsQHBwMXV1d9OrVC3369EGfPn1kXwft9u3bz/xy2LBhQ9kXg9X2hWVPnjyJ7777rtj1AwcOlD2Zh9zWIbn++OMP2NnZoVOnTnB3d0fHjh21NtX1w4cPpWsDNWjQAHv37pV+TZfr2LFjsq7B9jzavmjo09avX4+pU6fi8ePH+PrrrzWuGyTH33///cz3DSU/LgwbNgwBAQFo0KBBofeLXbt2YebMmbKLMl9fX/j5+eGPP/7A0aNH4ebmptHtNjw8XNGPYgVt3boVX375Je7evYtJkyZh9OjRLzST4OPHj7FgwQLMnz8fzs7O2Lp1q6wfJ16m9PR0/PLLL3j8+DG6dOkiu3g/ePCgRuHk5OSEjh07YsSIEVi3bp3iXi0WFha4cuWK9D73xhtvaKy/fPmy7AuaP68gyCd3mICTkxN++OEHjWW2trYaP26pVCpZ30Xy8vJk7VOuy5cva5yrHTt2oFevXhgwYAAAYNasWbInpFi0aJFWc3tacT9AvRbKYmAWFe/QoUNi6NChwtjYWDRv3lwsWLBA6OrqKpoYIp+zs7PWBuz7+fmJhg0bisePHxda9+jRI9GwYUMxevToMslNCCG+/PJLoVKphKmpqWjatKlo2rSpMDU1FWq1WnzxxRey4wjxZNB5o0aNRLNmzUSzZs2Ejo6OaNCggXQ//ybXn3/+KRo0aCANqlWr1dLEIcePH1ecW8HBtiqVSpiZmZVooG1CQoKwt7cXjo6OYs6cOWL79u1i+/bt4n//+59wdHQU9vb2IiEhQVFu2jpvI0aMEE5OTmLcuHGiYcOGQq1Wi27duokePXqI6Oho2Tk9T1JSkliyZIlo2rSpooG29vb24o8//ih2/cGDB4WdnZ2sWM+b5CAhIUFRbpUqVXrmhBBXr14VlSpVkh1PCO1MXCHEk8lzfvvtN/HFF1+IVq1aCX19fdGwYUPh6+srNm3aJO7cuaM4ZlZWlvj222+FpaWlqFOnjuxB60/T5mQTWVlZwt3dXejq6oquXbuKsWPHirFjx4quXbsKXV1d0bFjR5GVlaU47m+//SaaNGkiTE1NRWBgoEhLS1McQ5vHmW/AgAFCpVIJV1dX4e3tLby9vUW9evWEWq0W/fr1UxRr9erVwtvbW4wcOVLcvn1bY92oUaPEli1bFMWLjIwUrVu3FpUqVRKTJk0SycnJih7/tJycHLFy5Upha2srqlevLtauXSvy8vJKFOvSpUti8+bN4p9//hFCCLF7927Rvn178cYbb4hvvvlGUdzr16+LDh06CGNjY+Hp6SmuX78u6tSpI03oUKlSJdkTa6hUKuHs7CxWrFih6DOgOO+//754++23i13fo0cP8d5778mKFRISIt2Cg4OFoaGhmDt3rsbykJCQF865PDAyMhLXrl2T7jdu3FgsXrxYun/9+nVhaGiotf3lT7ghx/MmIlL6uVWRcbKJciotLQ0///wzgoODcfToUXTs2BEffPABvL29tfKLqVKJiYlo3rw5dHR04Ofnp9Gysnz5cuTm5uLkyZNlNnUxoL2L/ZXWlc5PnTqlcfHAkkxxq+2BttevX8eoUaOwd+9e6RcllUoFLy8vLF++XNHFeLV53pycnKTxVteuXUONGjUwceLEUhtvBTxpyZHbIjVs2DBcvXpVajErKDMzE15eXqhRowbWrFnz3FjavrBsq1atpGvaFCX/GjjHjx+XFU9bE1cU5eHDhzh06JA0Xur06dOoXbu2xniC4gghsHbtWkydOhU5OTmYNm0ahg8fXmi6cbm0PQmDNi8aevz4cXzxxRc4evQoRo4cia+++qrEU+0/fW0wbdm4cWORx/ree+9pdT9JSUmyWy+6d++O/fv3Y9iwYfj6669ha2v7QvveuHEjJk+ejOTkZHz11VcYNWpUiXsEbNu2De+99540SUR+Ny53d3fo6Ohg7969+Oabb/DFF1/Iivfee+/h5s2b8PPzw8aNG3Hp0iXUrFkT/9feeYdFdXx9/LtLEVCaJaKxoBEBu8beAAv2AtYYjQ3FlthQbEFjxK5YsEVF1Ch2RWMiVrBgw0Ys2FA0oagRVBBR4Lx/8HJ/LOzCXJjVRefzPPvw3J3ds7Pcu3PnzJzvORs3boRSqcTIkSPx8uVLpnTUU6ZMQXBwMK5duwZbW1s4ODhIO8j5ue6uXbuGJk2aoEuXLpg8ebKku7x79y4WLFiAw4cPIzQ0lHn8zYo2kjnkl1GjRmHhwoXSWB4QEICuXbuiaNGiAICEhAT069ePueSMvb09vL294erqihcvXsDKygoXL16UwmgvXbqErl27yopYUMe9e/ewceNGbNmyBTExMUzv0dPTQ2xsrDQfNTU1RXh4uDRniIuLQ9myZb+I5BXCkSoEZNaP2rp1K16+fIkPHz4wvY9nXRSA76Rbl+FdZ+X169coVqxYDnvp6elITEyUlfHs9OnTaNq0qawwHhbi4+MlB9TGxiZfRS95/t/09fXx9OlTKVzUxMQEYWFhsrPrZXL//n14eXlh3bp1amtmjRw5EnPmzGG+Gf/zzz+oX78+ihQpgtGjR8POzg5EhDt37mD16tVISUlBWFgYkwiYd2HZzZs3Y+TIkVi8eLFKyFdqairWrVuHSZMmYfXq1Rg0aFCetg4fPoxu3bppTFyxcuVKBAYG5jukKT09HZcvX8apU6dw6tQpnD17Fu/evWO6+dasWRORkZH48ccfMW7cOI2aH9bfl5OTE/bv389tvMyNtLQ0aaLBglKphLGxMYYPH57rOMsSfsTbYfxYHD16FBs3bsTBgweZs5wqlUro6+ujaNGiuf7GWMPAMs/Dd999l+t1xRLKWL9+fbRr1w5z5syBv78/Ro8ejblz50oJLX777Tf4+Pjgzp07TH2zsrLCwYMH0bBhQ7x8+RIlS5bEuXPnpKK+N27cQOvWrWUl60hMTMSZM2ekzH3Xrl1D1apV4eDgACcnJ/Ts2ZPZVmBgINzc3HL8ry0tLbFhwwZ0796d2VZWCupI8axZmFcBc7nOxfz587F8+XKMGjUKJ0+exPPnz1UWmZYtW4Y//vgDx48fZ7KXlbdv32Lnzp3w8/PD+fPnUb9+ffTo0QOTJk1ier9SqUSNGjWk+0t4eDjs7OykhYXU1FTcunVLOFIC3SI1NRUHDx5krnatrRsmj0k3SzFY1kxlvCfJPFds9+/fD09PT1y/fj3HRC8pKQn16tXD4sWL0aVLl4/et7S0NNy6dQs2NjY5tExv377FgwcPUKNGDWbHiGff8lrtksvw4cNhYWGBhQsXqm339PTE69evsWbNGmabkZGRGD16NI4ePaqysNC2bVv4+vpq1BN+DDw8PLB06VKYmprim2++AREhMjISiYmJ+Omnn5iSYAAZRRebN2+eI3FFJjNmzMDZs2cRHBzMZC89PR1hYWGS/uLcuXNISkrC119/LWUIc3JyYhLOZ70u1U2SKR8ZBYEM7cuxY8dw7949ABkFUtu2bZtvvZ865KYaZnG2FQoFIiMj87S1efNm9O3bt0D6oKzs2rUL3bt3lyZQ//zzD8qWLSudn7dv38LX1zdfmrCoqCj4+flh8+bNiI+PR4cOHdCjRw/mbHG8d/B5FiE1NTXF9evX8c033yA9PR2Ghoa4fv06atSoASAjC2C1atWYE+oolUrExMRIUSHFihVDeHh4vifx6nj58iWWLl2KlStXMpcpyMrbt28RFBQkFR+2sbGBs7OztGOTHwrqSGW/p2Qu4GVdrGT9beVVwFzuOUhPT8esWbNw6NAhWFlZYenSpSrlSnr16oV27drBzc2NyR6QUUJgw4YN2L17NypUqIA7d+7g1KlTaNGiBbMNQHuRO4WSjxxKKMiFnTt3UkpKinT89OlTSktLk46TkpJowYIFzPa0EQvPC57FYIcNG0aTJk3S2D558mQaMWIEc994/t/atm1L69ev19i+ceNGcnZ2ZrbHs2+bNm2ib7/9Vm1c9IcPH+jbb7+lrVu3fpK+8dapVa1aNVc9WlhYGFWtWjVffX358iVdvHiRLl68SP/995/s969atSpfn5sX58+fp59++ok6dOhAHTp0oLFjx8rWl5mamlJERITG9oiICDI1NZVlT6lUUtmyZen777+nDRs20IMHD2T1KZPg4GCmhxwCAwOpVKlSKsVCFQoFlSpVKteis3LRheKXu3btIhcXF6pevTpVr16dXFxc8qUvy17g19TUtEBaiZSUFAoICKDWrVuTkZERde7cmfT09Cg8PFx233QZ3hoTbWhW0tLS6MKFCzR//nxq3749mZqaSvqpQYMGybKlLXgWCS+ovU+hG2LVNS1evJiqVatGX3/9NXl4eND169eJiApUlF6Qgcjap0N89913Kiv61apVU9kWfvPmDaZOnSprZY9XXZSYmBj4+vrC29sbANC8eXOVlTI9PT0cOHCAua4Pz7pUISEh+P333zW29+7dG/369WOylQmvbDM3b97E6tWrNba3bNkSM2bMkGWTV982btwIDw8PtZoSfX19TJ48Gb6+vrJSmPPqW/ZVrG7duhXI3pMnT3LdKStZsiRzkU9AdffN0tJStg4vKzNmzEBgYCA2bdrEHOrFQuPGjQtcBDktLS3XsgcGBgayVqUXLVoEJycnldpU+YV3RsHQ0FD07NkTXbt2xcSJE1WKLC9ZsgQ9e/ZESEjIJy0szYP09HR899132L17N6pWrSplh7116xb69OmDXr16ISAggPm3TNmCWrIfy+HHH39EQEAAbGxs0L9/f+zcuRMlSpSAgYFBvrVvmX26cuUKHj9+DIVCgUqVKqFu3bqfNKuYQqFQ+fzsx/nBy8tLinx4//49vL29pRTwcur5ZBbIPXfuHN68eYOvv/4ajo6OWLZsGZycnGRHBvAMn8teyDj798yENVNkYUWursnT0xOenp6YPXt2gX5LWblw4QIOHTqE9+/fo3Xr1mrLvHwJCEdKh+B5Q8qEV12U1atXq9RtuXHjBoYMGSKJfv/66y/4+PgwOz8861LxniQD/OqsxMfH51qf4cOHDxrr4Whi0KBBeYbl7Nu3L087d+/ezXVS2KBBA+b4/Ex4/d94hwOYm5vj4cOHGkPGHjx4IEurxuO3mcnNmzcxbNgw1KhRAytWrOBWe+v+/fsIDAyUJo+VK1dGt27dZIXAVK9eHYGBgRoTVxw4cIC5RhCgWk9FHUSE58+fM4WH5lbwNius53XOnDkYPHhwjtTxTZs2RdOmTeHu7o7Zs2czC8V5wnMiunz5chw/fhwHDx7Mka784MGDGDx4MJYvX56vIt8FZc2aNfD09MSUKVNgamrKxeapU6cwdOhQREVFqYTgVqpUCX5+fsyFroGck3hNsIxx9P8JOTKdp8TERNStW1cKiZQ7xrRs2RJ3796Vjps2bZojHI31uy5btgyOjo5YvHgxnJycChymzBJKzJpiPHshY3Xf81M6yLycWXWo0zWxXpO//vorNm3ahK1bt+K7777DgAEDpDDS/LBnzx706dMHxsbGMDAwwNKlS7FgwQJ4eHjk22ZhRThSnzm86qL88ccfOW7mY8eOlSZljRs3xoQJE5gdKZ51qXhPkgF+dVasra0RFhamsSZYWFiY7EKKpqamXPQaSUlJuU5G37x5I3vg51mfhictW7bEypUr0apVK7XtK1askB0jzouyZcvi8OHD8Pf3x08//YT9+/dj+vTpORKKsOwcZzJv3jx4eXkhPT0dX331leSgeHp6Yu7cucw3u9GjR2PkyJEoUqSI2sQVM2bMyHXHNTsmJiaIioqSxqROnTphw4YN0m/92bNnzBoCCwuLXK8nOQtFQMbqam675KNHj2beBQsPD8+1PeuElwWeE9FNmzZh0aJFamvEde3aFQsXLvxkjtTWrVvh5+eHMmXKoFOnThgwYEC+C44DGWN/586d0ahRI/j4+EhJYW7fvo0VK1agY8eOKjqivMg+iT979iy+/fZblfGYdYyTWwcvL1h1iixER0dzswWwJ8phgXchY57wdGazwkPXNHXqVEydOhUhISHw8/NDo0aNUKVKFRCR7MVcIOMeM2zYMKxatQp6enqYN2+erHvLZ8XHjyYUaELbMdMFwcLCgp4+fSodu7i4qNSXePToERkbGzPb41mXqlevXrnqqbp27Uo9e/Zk7hvP/9u0adOoQoUKamtxxMTEUIUKFWjatGmfpG+1a9emNWvWaGxftWoV1a5dm9ke7+ste20sS0tLsra2JmdnZzp69Kgse1evXqUiRYpQjx496OLFi5SQkEAJCQl04cIFcnV1pSJFitCVK1eY7SkUCvL29qbly5fn+pDLsWPHSE9PT6o1lvUvKydPniSlUkkzZ86kly9fSs//999/9PPPP5Oenh5zPRkiookTJ0o12urWratSo23cuHGyvh/LGKdQKJhs8dZIGRkZqdRsyc7jx4+Za7ZkPXfZH/k5pzwxMjKiqKgoje1yvidRxnfdsmULBQYGUmBgIJmYmNBvv/0mHW/evFn2d42MjCQvLy+qUKEClSxZkpRKZb70W6NHj6ZWrVqpbUtPT6dWrVrRmDFjZNvNhLc+R9e4dOkSjR8/njp16kSdOnWi8ePH0+XLlz9pnyZOnEh37tzhZu/Vq1cqD1NTU7px40aO5z8F2tQ1vX79mtauXUsNGzYkPT09atKkCS1ZsoT5/UWLFqX79+9LxykpKaSvr6+zunxtIrL26RBKpRKbN2+WtoG/++47LFu2TMrCk5CQgMGDBzOvsPLM2lesWDGcOXNGY1X5a9euoUWLFkhMTGSyx7MuVWaNis6dO2Py5MkqthYuXCi7RgXP/9ubN2/QpEkTPHnyBP3791fp27Zt21C+fHlcuHCBOYyFZ98WLlyIhQsX4uTJkzl2OzJT5U6ePJlZk8cza5+mbFsJCQm4cuUKdu7ciT179jBnOwQydlWHDBmC//77T+X5EiVKYMOGDejatSuzLaVSiXLlyuUaa86a6SmTpUuX4ueff0avXr3w888/59iRYt257NOnDywsLHKEqGUyfPhwvHnzBgEBAcx9u3DhAgICAqRsW1WrVkXfvn1l64V4ZrXasmUL+vTpwy37XK1atTB+/HgMHjxYbbufnx+WLVuW524TkJFtjgW5u9E8KF68OIKDgzXucP79999o2bIl8yo1a1bP9PR05j5mQkQqac9LliwJV1dX5lDHGjVqYN68eRrHiUOHDmHq1KlMdcvUwaOGEXHSb/EMOwSAyZMnY/HixShWrJj0/R4+fIi3b9/Cw8Mj193b7PAMTbWxsUFkZCQaNWoENzc39OnTp0BZ/zLreGVC/7+Tnf34U6Tx1tfXV6trMjAwwI0bN/JdDiQ7f//9NzZu3Ijt27fj2bNnTO9RNxfRpZpeHxPhSOkQvG9IPOuifPvttxgyZAhGjx6ttn3FihXw9/fH1atXmW3yrEvFe5LMM238q1evMHXqVOzcuVOanFhYWKBv377w9vaWlT6eZ98+fPgAZ2dnnD17Fm3atJHCDyMiInD8+HE0a9YMx44dy1XLpq2+5cXSpUuxZ88ehIaGynpfcnIyjhw5olK02dnZOU9dV3Z4ftfIyEgMHDgQ9+/fx7p16wqcWKNSpUrYunUrmjdvrrb9zJkz+OGHH7iG27DC05HiXVjWx8cHc+bMwdatW3PUxTp8+DAGDhyIadOmMU9YecJzItqpUydUqFBBY6r/ESNG4MmTJ59EC5aSkqLRMX758iW2bNmCTZs24caNG0z2zMzMEB4eDmtra7Xtjx49Qq1atfDmzZt89begE0ee+i0nJyeVY01hhyyp2Tdv3owRI0Zg0aJFcHd3l+4BHz58kHRs69atww8//MDUN54pxoGMeop+fn7Yu3cvgIw04G5ubmjatCnT+7MSEhLC9DqWsF7ezuy8efOwadMmvHv3TkXXxNuRyuTDhw+y7vfZC8l7enpi0qRJKkWbWcakQs8n2gkTfETevn1LgYGBtGjRIlq0aBEFBgbS27dvZdlYuHAhFS9enG7cuJGj7fr161SiRAlauHBhvvr38uVLunTpEl28eFElFEkub9++pX379tHChQtpwYIFtH//fkpKSpJtx9ramv7555989yMrlSpVohcvXhBRRijJs2fPKC4ujtLT0/NlT6FQqIRYFpT379/TggULqHbt2mRiYkLGxsZUu3ZtWrBggUoqfhb8/f3p3bt33PqWG3fv3iVLS8uP8lnqyJ7yuSAULVqUevToQc+fP+diz9jYONdr5OnTp7JCt4iI7t27R4sWLaLRo0fTmDFjaOnSpfkKaVIqlfTs2TPp2NTUlCIjI6VjOeHLvMs7pKWlUc+ePUmhUJCdnR25uLhQ9+7dydbWlpRKJbm6uqqUo8iNBQsWqIyxZ8+eVfltvH79mkaOHMncN2tr6zwflSpVYrJ17tw5MjAwoF69etHFixfp1atXlJCQQOfPn6eePXuSgYEBnT17lrlveREXF0fe3t5Mry1SpAg5OjrSL7/8QqdPn6b3798X6LPzukYKmo66IKF99+/fJxMTE3JycqIDBw5QREQE3blzh/bu3UsODg5UtGjRAoUNFqRvDRo0yLU8yZIlS6hBgwb57Rq3kMjExETauHEjNW/eXPrdLlq0SG0ovSY2b97M7b7l6OiY58PJyUm23eDgYPrhhx/IxMSEatWqRXp6evn6jb59+5bOnDmjNiwwOTmZNm/ezGyrYsWK3Makwo5wpAoRcm5ImfCqi/L+/Xtq2bIl6evrU4cOHWjcuHE0btw46tChA+nr61OLFi0KfNMjyojPv3XrFvOERRvwnCTznuzxtMfzexKRpInI68GD8PBwKl26NPPrQ0ND6dChQyrPbd68maytralUqVI0bNgwWTdTnudBTq0uFnhPHufOnUv6+vqkVCrJysqKSpcuTUqlkgwMDGjRokWy+5ZV/6ZQKMjc3Fw6trCwkOVIZXXKeLFjxw7q1q0b2dvbk729PXXr1o0CAgJk2eBdW4k3+/btk7RHWR8lSpSgPXv2cP0sOTWzNm3aRAMHDqSKFSuSQqEgExMTatOmDc2dO5fOnz/PXDMnE4VCQadOnaIbN26ofZw4cULWecj+/qJFi9Lhw4dzPM+CLuu3TExMcn3vw4cPycTEJL9d04q27P79+zRt2jQqXrw4GRoaMr+P931QmxRE13T37l3pd6VUKqlly5YUHR0ttX/qMakwI0L7ChE3btxAvXr1mGN1Q0ND4ejoqLEuyh9//CGrLsr79++xdOlS7NixA/fu3QOQEa/83XffYfz48bK0Cn5+fkhISFDZCh8+fDg2btwIALC1tUVQUBDKly+fp62TJ09izJgxuHDhQo7sfK9evULTpk2xdu1a5gw3PMO2eIe76Xrf8oJXrPm4ceMQERGBI0eOML2+Q4cOcHR0hKenJ4CMmPB69eph0KBBsLe3l0JYZs2axWTvl19+waRJk2SHBKqDdxpvdSEXWXnz5g28vLyYzsOpU6fQpk0b/Pzzzxg7dqwUhvry5UssW7YMc+fOxcmTJ5lDkDRp37IzcODAPF+jVCpRo0aNHFqy7LCGG/PUXPEMYdQWb9++RVBQkIruLT9hrnkh976VSWRkJIKDgxESEoLg4GD8888/KFq0KFq0aIHDhw8z2cjUv6ib5sgtAcLbni7rt8zMzHDp0iWN2Wbv3r2LBg0aMI9dPPumjqSkJOzatQsbN25EaGgobG1tmUt3fMyQdJ7I1TW5uLjgw4cP8Pf3R0JCAsaNG4fbt28jODgYFSpU0IkxqbAiHKlChNwbUseOHVG+fHmNonN3d3c8ffr0k8TCN27cGO7u7pKw+8iRI+jSpQv8/f1hb2+PMWPGoFq1atiwYUOetrp27QonJyeNtW5WrFiBU6dOYf/+/Ux9y570I7fP/Zi2Mu3lNknOhCUuWZdvIJpizV+9eoWrV6/i3r17OH36NL799lsme2XKlMGhQ4dQv359AMD06dMREhKCs2fPAgB2796NmTNn4vbt20z2Xrx4gaSkJJVkAbdu3cLixYuRlJSE7t27MxeBzi52zo7cyZ61tTWTUJ1FI6WNxBW8UCqVmDhxYp6/BdaaZDw1V9pwpNLT0+Hv7499+/apJCbo2bMnBgwY8Elr5+RGfh2prDx69AgbN27EypUrkZiYyGyLd9IPnvZ0Wb/l6OiIFi1a4Ndff1XbPmPGDJw9ezbfKdd5OVJnz56Fn58f9uzZAyJCr169MHToUDRr1ozZhlKpRFxcHJcyMUCGU7dgwQK1v1MPDw/uCxWsuqbSpUvj+PHjqFmzJoCM+8qoUaPw559/4tSpUyhatKjsMSk5ORlXrlxB8eLFc+i13r17h127djHr6Aozoo7UZwzPuii8uX//vjSpBYDAwEB069YN33//PQBg7ty5GrNnZefGjRu5fk9nZ2fm+laZ5LUiLmdiy9MWAKxduzbPbHGsAs8NGzZwccp4k71eSyZmZmZo27Yt9u3bJysZSXx8vEoGyJCQEJX6NA0aNJBVtPnHH39E2bJlsWTJEgAZ9Y9atGiBsmXL4ptvvsGgQYOQlpaGAQMG5Gkra10UIkLHjh2xYcMGfP3118z9ycrjx4/z9T51XLp0CVu3btXYPmDAAFk3yvj4ePz+++8YOHCg2t3jLVu2qG3TxKRJk7gtBOjymiIRoWvXrvjzzz9Ru3Zt1KxZE0SEO3fuYNCgQdi3bx8OHDjAZItn4gpt8eTJE5w6dQrBwcEIDg7Gixcv0LhxY3h4eMi6Z/HOirh582Zuk+HExMRc7ZiYmMiq45c9myQRISIiIkcmXZZ6dB4eHujevTtSUlIwceJEaeyMjY3FkiVLsGzZMuaFSSDnrrtCoUBiYmKO51l+9zExMdi8eTP8/f1x7949NG7cGEuXLkXfvn3zvJdponXr1lx2tt+/fw8HBwfcvHkTHTp0QJcuXaTfqbe3N/766y+cPn2aOaFDcnIyTpw4IdV8mzp1KlJSUqR2fX19zJ49m8lecnJyjuQea9aswZgxY+Dg4IDt27cz9SmTe/fuwdnZGU+ePIFCoUDz5s2xY8cOqSbgq1evMHjwYOFICQo3ycnJuQ5M5ubmePfuHZMtS0tLphXPly9f5qtvoaGhGDp0qHRcuXJlxMbGMtmKi4vLdSDR19fH8+fPmWxlwnOnhveuT1hYGDd7PJ2yTHbv3o2AgAAp/LNq1aro168fevbsyWyDd9HF0qVL49GjRyhfvjzev3+Pq1ev4pdffpHa37x5w3xzAzIWKfz9/aXjLVu2oHjx4rh+/Tr09fWxePFirFq1ismRyj4x1NPTQ+PGjXUihWxcXJzGFXMgIxsX6+8UAHx9fREeHo4ff/wxR5u5uTnOnDmD169fY/r06Xna0sYODE+bWRcpUlNT4e/vL2WzkrvL4O/vj9OnT+PEiRM5srOdPHkS3bt3x5YtW5gmLTyL+wJ5ZyqTM/YOGTIEwcHBePnyJZo1a4YWLVpg+PDhaNCgQZ4TXXU8efKE6XUVKlRget0vv/yCESNGcNtVuH37tsbfz4sXL2TZqlOnTo6ww8wJuNyww86dO8PHxwceHh5YsmSJFFHx6tUraXxTV9BZE9mLZxORSikVOX0rX748SpQogQEDBmDo0KGSZKEgtGvXLt9OWFbWrFmDf/75Bzdu3JBKnWQSEREBR0dHrF27Vu34p47Nmzfj8OHD0v/a19cX1atXlzIxRkREoEyZMhqjcbJiZ2eHsLCwHP8vX19fAOxRMZl4enqiRo0aCAsLk0IFmzVrJoUKfkkIR0qH4HlDAjL0SydPntS4s3PixAnY2Ngw2Vq2bJmsz86LihUr4sqVK6hYsSJevHiBW7duqWzHx8bG5hkOl8nXX3+NmzdvokqVKmrbw8PDpVUSFnhOpnhP9njb4+mUpaen47vvvsPu3btRtWpVKb7+1q1b6NOnD3r16oWAgABu32HPnj3MzlnHjh0xZcoULFiwAAcOHICJiYmKZi48PBzffPMN82fHxsaqOBgnT56Eq6urNNnr2rUr5s2bx2yPJ1u2bGF6Hcuk+927dzA0NNTYbmBggPfv3zP3be/evdIunjrc3d3h4eHB5EhpYweJ18p0hQoVsH79eunYysoqx86enMlGQEAApk2blsOJAoBWrVphypQp2LZtG9M55Z32XtPucVZYNXT+/v6oUKECpk+fjtatW+ernlJWNIW5UpZaQQqFAqmpqUz2eF9zrVu3zlNvxQrv8/rjjz/CxcUFu3fvVtHR9ejRg0m7nBWeC2O7du1C165d8+VYa4LXzva+ffvw888/53CigAxHZvr06dizZw+zI7Vt27YcdRy3b98uLbL9/vvvWLVqFZMj5eLigoCAALWLe76+vkhPT8fatWuZ+gVkLH4fP34cJUuWRMmSJXHo0CGMGjUKLVq0kEIFvxSEI6VD8LwhAcDgwYPh4eGB0qVLq62LMnnyZEybNo3JFov4Ww4DBw7E6NGjcevWLZw8eRJ2dnYqepfQ0FDUqFGDyVbHjh3x888/o3379jAyMlJpS05OxsyZM2WtnvG8WfK+8fK0x9spW758OY4fP46DBw/m+H8fPHgQgwcPxvLlyzFu3Dgme6mpqYiIiIChoSGqVq0qPR8YGAgvLy9EREQwO1K//vorXF1d4eDggGLFimHz5s0qDoKfnx+cnZ2ZbAEZISgJCQlS6NClS5dUdlQVCoVKCMbHZOzYsRrbFAoFkpKSkJqayhxykVv4p9ydlYcPH+a6eGNjY4OHDx8y2Xr06JFKvZLMFfysz8mF18o0z/BKIMPRX7hwocb2Dh06MIfs8YbnJPnOnTtSSN+SJUuQkpKC5s2bw8HBAY6OjqhXrx5zvUVA8z2ViLBjxw6sWLFC9vnmNW7ydnx4hh1mUq5cObWT9PDwcNSvX595EYWnhMDV1ZWbLYDvffD27dtwdHTU2O7k5ITZs2cz23vw4IGkaQIAIyMjleu/YcOGGmt7Zmfq1KmYOnWqxvbVq1dj9erVzH3jHSpYqPkYqQEFnwaedVEyyV6T6uDBg7JrUmX27eeff6Y6depQ+/bt6fbt2yrtPXv2pA0bNjDZio2NpbJly1L58uVpwYIFdODAATpw4ADNnz+fypcvT2XLlpVVV2LQoEH0+vVrWd/nY9giIpo1a1a+amOpg3dq9po1a9LGjRs1tm/YsIFq1qzJZOvvv/+mihUrSmmZXVxcKDY2llq2bEnFixcnT0/PfNXTSkhIUJtC+b///pNVN6tr1640ZMgQSktLo927d5OhoaFKDbQ//viD7OzsZPePKCM1cNbaSryIjo4md3d3MjAwoHbt2jG9h6VWiLW1NXMfzM3N6fz58xrbz58/T+bm5sz24uPjadSoUVSiRAmVFN6jR4+m+Ph4ZjtEfH8PTk5Osj8/NwwMDFRSFWfn33//lZXyOS0tjTZu3EidOnWi6tWrU40aNahLly60efPmfNe40wa3bt2i1atXU69evah06dJkbm5OnTp1KpDNY8eO0bfffkumpqY0c+ZMWeNz9vT9mh6fgo+ZxltOSnveZKbvzu2hp6cnyx6v/5u+vj7FxMRobI+OjiYDAwNme0ZGRhQREaGx/c6dO1SkSBFZfeRFgwYNaMuWLWrbRo8eLauURWFHZO3TMV6/fo1ixYrlWHVLT09HYmIiswg7Kzt37syhWenbty/69u0ry87Bgwfh5uaWI3a7ZMmS2Lhxo8Y0rh+DqKgojBw5EkFBQSoV4tu1a4dVq1bJSkyQkJCAgIAAjBw5EgDw/fffIzk5WWrX09PD+vXrYWFh8VFtARlCW19fX3h7ewMAmjdvriJI1tPTw4EDB5gSFfBM4Q0AxsbGuHv3rsaQpaioKNjZ2al8f0106tQJKSkpGDduHAICAhAQEABbW1sMHToUo0ePlmLEeSInVDA8PBytW7fG69evkZqaimnTpqlkuBowYACKFi3KFCqRfYX10KFDaNWqVY7QiH379jH1LTtv3rzBggULsHz5clSvXh3z5s1TGyL2MXByckKjRo0wf/58te2enp64dOkS0y7Hy5cv0aRJE/z777/4/vvvVco7bN++HeXLl0doaKiUsj0vtJm1r6Do6ekhNjZWY2YxOVkAiQhdunSRElfY2dlJgvi///4bXbt2ZU5cAQDVqlXD2bNnUbx4cQDAqFGjMHv2bGln8NmzZ7C2tpaVOCH7dzt16hROnTqFHTt2yMral5WrV6/C09MTZ86cgZubG7y8vGSfH6VSiWXLluUZds4SwcFbv/Uxs7DKzcSYV2ZSgD3E8sCBAxptnT9/HitWrEB6ejqz/jsqKgoVKlTgsjPF83cKZOzQz58/Hz169FDbvmvXLkybNg0PHjzI0xbrTh7rfWbevHk4c+aMxqzPo0aNwtq1a5Gens5krzAjHCkdYv/+/fD09MT169dzTG6TkpJQr149LF68+JM4LLxrUmWSnJyMY8eOqTh5bdu2zfdEOT4+Hg8ePAARwcbGhnkSlZXFixfj2rVr2LZtG4CMVK3t2rWDqakpgIzBum/fvkw1h3jaAgAvLy+8ePFC2oI3NTXFkCFDpEnMX3/9hebNmzNlKeTplAFA8eLFERwcrDEr1N9//42WLVsiPj4+T1tfffUVjh49ijp16uDVq1ewtLTE5s2bmZI3aIIlVFBOON6LFy9w7tw5WFlZoVGjRipthw8fRrVq1ZgceNbslJs2bWLuG5CRFnflypWYO3cuSpQoAW9vb1kJP7TB3r170bdvX/j4+GDkyJFSopO0tDSsXr0aEydOxPbt25n6OW7cOJw4cQLHjx9XycgIZGjYnJ2d0bp1a6bkCoDu12jr0KGDxhpXKSkpOHLkCNMEbdOmTRg7diwCAwM1Jq7w9fVlDv3M/l3NzMxw/fp1lVTvZcqUYZ5QPXv2DMHBwVKI371792BoaIiGDRvCyckJTk5OskLFHj58iGnTpmHv3r3o3bs35syZk+9ELryvEZ76Ld5pvHNDriMVGBiosS0/zk927t69iylTpuDQoUP4/vvvMXv2bOaMjTwXAvKqbZeamopbt24x/9/Gjh2L48eP48qVK2plC/Xr10ebNm2wfPnyPG1lv89s374dXbp0keYimci9zwiEI6VTODs7o3fv3nBzc1Pb7ufnh507dyIoKIjJXnR0NJYuXQovLy+1qYbnzJkjaajyQhs1qbS9wxUVFYWkpCTY2dnJiqtv1KgRvL290aZNGwA5a17s378fs2fPZtK08bQFAHXr1sWKFSukRAnZ7QUFBWHChAm4detWnrZ4OmVAxi5ShQoVsGbNGrXtI0aMwJMnT5iuEXV1eK5evcqcHCU7N2/eROfOnaUU5926dcOaNWvQu3dv3Lx5E8OGDcOYMWNQrlw5ZptEhAcPHuD9+/ewtbXlKn4uCESELVu2wMvLC6mpqZg5cyaGDh2aa3ZGTfBMXJHJ9OnTMW/ePJiamkrXbWRkJBITEzFp0iSNu1XZsba2xrp169CuXTu17UeOHMGIESOY9UpRUVEoX768NFYURHOlVCpx8uRJ6bekCZZU1ABfZ9vZ2VlKUKGOuXPnIiQkhPk+w7Nmlr29Pe7duwd9fX00aNAATk5OcHR0RLNmzXJMJFkYNWoUNm7cCCcnJ8yfPx916tSRbSMrPHctb9y4ofZ5yqbfYim2CmScB3Nz8zx3Vlgy6+ZVaDc8PBwODg4Fqg1WEOcnk+joaMycORObN29Gu3btMG/ePGZtdSY8FwKyZoLNDdbadnFxcahTpw4MDQ0xZswYaQHw7t278PX1RWpqKq5du8Y0h8sO76LIXzSfIp5QoJ4yZcrQ/fv3Nbbfv3+fypQpw2xv4sSJNGzYMI3t7u7uNHnyZCZblpaWFB4errH9xo0bZGFhwdy3c+fOkYGBAfXo0YNCQ0MpPj6e4uPj6dy5c+Tq6kqGhoa5aimysnHjRlqyZInKc8OGDZPipe3t7enJkyfMfStZsqTK67/99lsVPc7Dhw+paNGiH90WEZGFhYXK+zO1Q5k8evSIjI2NmWzVqVOHTp8+LR0XK1aMHj58KB0fOXKEqlWrxty3zHPaq1cvunjxIr169YoSEhLo/Pnz1LNnTzIwMKCzZ88y2VIqlfTgwQPJhqmpKd24cYNevXql8mClY8eO1Lp1azp06BD169dP0g0uWrQoXxq/yMhIqlGjhnSNVahQgS5fvizbjjaoUaMGmZiYkKenJ8XExOT4n8n531lYWGh8WFpakqGhYb7i4C9evEg//fQTdezYkTp06EBjx46lixcvyrJhaGiYq07u6dOnsvUDvDRXmToOhUKR45H5/KfSD5QuXZquXbumsf3q1atUunRpZnvZNSbZx5HY2Fjm7zplyhQKCgriqgM1NjamunXr5vqQY0+bOqSC6reWL19O/v7+uT5YbeWmQSrI9fvvv/+Sm5sbGRgYUOfOnenvv/+WbSMhIYEmT55MxsbG1KRJE5X7mFx4Xr/aIDIyktq1a6cyniiVSmrXrp1KP+WS/XvKxcXFhenxJaAbS6gCABlhablt43/48IEpLCqTI0eO5KrR+OGHHzBs2LBci9lmwrMmFQDMmTMHgwcPzrHD1bRpUzRt2hTu7u6YPXs20+7Fb7/9Bnd3d+n4yJEj2LRpE7Zs2QJ7e3uMGTMGv/zyCzZs2MDUt6SkJLx69UpK8RoWFpajnTVMhactIOMaeP78ubRzkj2eOT4+nnn37fHjxyqhZ23btlXR5dja2srKLNW0aVPs3LkTw4cPx969e1XaLC0tERAQwFxxnohUwu+oAHVHAODy5ctSqGCLFi2kdNL5DRWcNGkSUlNT8fvvv8PIyAiLFy+Gu7s7rly5ItsW79j1zN3IhQsXYtGiRTna5fzvNI03MTEx+OWXX+Dn54e2bdsy9QvI2BmsUaMGGjZsiIYNGzK/Tx0lS5bE48ePNe4iPnr0KM8doazkprny9/fHiRMnZGmuLl68+FHCrOTy8uXLXFewS5cuLes+o1AocuyC5FdvwrtkAOvKPytZx+qEhARJm1KlShVmnas6suu3/vzzz3ztevXt25fLbhnvOn5ARhTM3LlzsXLlStSpUwcnTpxQKUHBysKFC7FgwQJYWVkhICAA3bp1495XHoSHh6tIFlh3n7NTqVIlHDlyBC9fvlS53uSMbdogu05QU6jgl4BwpHQIa2trhIWFSfV3shMWFiZr6/vRo0e5ClXLlSvHHPbCsyYVkFHQNDcHbvTo0cxx8Pfv30f9+vWl48DAQHTr1g3ff/89gIxQFdbQGCCjGPDVq1c1hgiEhYUxJ6/gaQvIcG5CQ0NVnIqsnDlzRsUByQ2eTlkmLi4uaNeuHYKCglRqjzg7O8tKasH7Rv7ixQuULVsWQMYNoGjRorL1fFk5e/Ys9uzZg+bNmwMAGjdujHLlyiEpKUl2/QzWemmsaGMSlEn2xBVBQUGyElfUqlULDRo0gJubG/r27Vugm267du0wffp0HDt2LEetq5SUFKkkAiuzZ8+GoaEhHj58mMPRmD17NpydnTF79mxmzVWFChW4aaR4OttpaWm5hqHq6ekx63KADMc8a/2t5ORkdOnSRToncmwBGYtLCxYswL59+/D48WMoFApUqlQJPXv2lJ3em7cjBWQsQI0ePTpHYqP27dvD19c31wLW2cmu37p9+3a+Q614pvHmma4c4Ov8TJkyBcbGxqhSpQo2b96MzZs3q30d68ITz4UA4H+lMG7fvq1yfVSvXh0bN25EgwYN8mW3ePHiORafiAjPnz//KAlGspM9jHjPnj1YuHDhFxkqKBwpHcLV1RXTp09H27Zt1YqnZ8yYgf79+zPbMzY2xuPHjzU6U48fP2ZO6sCzJhXAd4cru63Q0FCVmj6VK1fWWD1eHS4uLpgxYwbatWun9jzMnDmTWRPC0xaQseLo5eWFFi1a5FjhunHjBmbPng1PT08mWzydsqyYmJjAxcVF9vuyYmNjIzk+PFAoFHjz5g2MjIykHZnk5OQcWgDWrJjPnj1TWTgoU6YMjI2N8ezZM1mOMcBf3Mt7EgTkTFyxadOmfCWuCAkJwaZNmzBx4kSMHz8ePXr0gJubW75WpmfPno369evDxsYGo0ePVsk+t3r1aqSkpOQogpsbBw4cwLp169Tu1lhZWWHhwoUYMWIEsyPFE56rv0SEQYMG5Zq4Qg7ZnRV1k2RNWcey8/79ezg4OODmzZvo0KEDunTpIp1Tb29v/PXXXzh9+jQMDAxk9ZEXT58+RePGjWFgYIBff/1VZddyzZo1aNKkCS5fvsyktcyq3woLCyuwfot0WO7O0/n54YcfuDqNPBcCbt++jdatW8Pe3h6///67yvXh4+OD1q1b48KFC6hWrRqTPRMTE0RFRUk72506dcKGDRtQpkwZABn3IVb94cGDB1WO09PTceLECdy8eVPl+a5duzL1TfA/RLIJHeLNmzdo0qQJnjx5gv79+0vVsSMiIrBt2zaUL18eFy5cYL55durUCWXLlsX69evVtru5uSE6OpopfC49PR19+vTB3r17YWtrC3t7e+kGd//+fXTv3h27d+9m3sGoVasWxo8fr3GnyM/PD8uWLUN4eHietuzt7eHt7Q1XV1e8ePECVlZWuHjxolTg99KlS+jatSuzM/XmzRs0atQI//zzDwYMGKAi8Pz999/x9ddf49KlS0zngactIGNC26ZNG4SGhqJt27bSNXL37l0cO3YMTZo0wYkTJ5gmGosWLcL8+fNx6tQptU5Z69at4enpiUmTJjH1bcKECWqfNzc3R9WqVeHq6qpx8pYdS0tLrFq1Cv369WN6fV5kz5BFWTJjZT1mDRXU09PDvXv3VEK3ypUrh7Nnz6qsSOenXEFByUsonglL34hj4oqsJCUlYdeuXfD398eZM2dQpUoVDB06FAMHDoSVlRWzncjISIwePRpHjx5VWf1t27YtfH19UaVKFWZbRYoUwcOHDzVOgv/55x9UqVKFaYHHyckJ+/fvL1C4V24URCiurSyRPFi+fDnmzZuHkJAQaWzLJCIiAo6Ojpg+fTp+/PFHJnt169ZlmnRfvXqVyd7QoUPx4MEDBAUFqc2i1r59e9jY2DCFkSuVShgZGWmMQJHbt6wUNOyQZ7pyABg0aBDTefgU1xzPBBG9e/dGamoq9u7dm+P7EhFcXV1hYGCAXbt2MX0mSyIX1kQYLHMzOffA7HzJySuEI6VjvHr1ClOnTsXOnTulOHULCwv07dsX3t7estJ5nzp1Cm3btsW4ceMwadIkaaU1Li4OCxcuxPLly3H06FG0atWK2SavmlQ+Pj6YM2cOtm7dqnaHa+DAgZg2bZrGyXlW5s+fj+XLl2PUqFE4efIknj9/rrLKsmzZMvzxxx84fvw4c//i4+MxdepU7Nq1CwkJCQAyzkPv3r0xd+5cWfHJPG0BGau2S5cuxY4dO6TzYGNjg++++w7jx49ndlZ4OmUANIZ4Zd7US5cujZMnTzLVRVm9ejU8PT3Rvn17rF27FiVKlGDqgyZCQkKYXse6m6NuopHVOZPjmA0ZMiTP1ygUCmzcuDHffVPXT5a+1axZE5GRkfjxxx8xbtw4jWFVBXEYHzx4gE2bNmHr1q2IjY1F+/btc6ye5kV8fLwUSppf/cDXX3+NnTt3SuGa2Tlz5gz69OmD6OhoZpu8yztkoquTloLqQhwcHNC7d2+MHj1abfvKlSuxZ88e5t8z7yxqeV0jp0+fRt++fZmuEd59A/iFHWo7XfnnSqlSpfDXX3+pSA2ycvnyZXTs2BHPnz9nssczI6a20dUx6WMgHCkdhYjw4sULEBFKlSqV763sdevWYezYsfjw4QPMzMygUCjw6tUrGBgYSLVcPgU8d7jS09Mxa9YsHDp0CFZWVli6dKm0pQ4AvXr1Qvv27VXC/VjJjEEGUKDzwNsWL3g5ZXnx+vVrfP/99zA1NcX27duZ3vPo0SMp1nz9+vUFSocfHR3NNVSQp2OWWxhkWloajh8/jpSUFOabZXBwMNO1xdK3rL+/3GreFPRGnpSUhG3btmHq1KlISEhgrofUqlUr2SmTNTFkyBA8fPhQo+aqXbt2qFy5Mvz8/JjsabO8g65NWnjpQkqVKoXg4GBUr15dbfvNmzfh5OTEPBHlDc9dS948ffoUDRo0gIGBAUaNGpUj7DA1NZU57FAdPNKV84B3cp6sFHQhwMjICPfv35eSS2Xn6dOnsLGxYb4+dNmRyr7Y9d1332HZsmU5QqO/hFBB4Uh9Afz777/YtWuXVKi2atWq6Nmzp6wBlWdNqqzw2uHiSeYqspOTU46Qu9evXyM4OBjt2rVjcjJ42gIyVt5///13DBw4UO152LJli9o2XeDSpUvo1asXoqKiZL3P19cX48ePh729fQ6RPGvYC+9QQd6OmToCAwMxbdo0REdHw9PTU2PdH23CeycvO6dPn4afnx/27t0LpVKJ3r17Y+jQoUyJQIyNjfH+/XtUrFhRKtTq5OTEXEA6O//88w/q16+PIkWKaNRchYWFaZwkZUVbBcwzKYgjxXsievv2bTRq1Aj29vbS7zTzeR8fH9y9e5dZF2JgYICnT59qDO+MiYlBxYoV8f79e6a+8cba2hq//fYbnJ2d1bbLrV3GE55hh1nhUauJ5zWnjdBUXgsBtra2mDt3rkZN4J49ezB9+nTcvXuXyZ6enh5iY2OlEHIzMzPcuHFD0uHKcaRGjRqFhQsXolixYgCAgIAAdO3aVUqOlJCQgH79+jHXAtV2qGBhQjhSOoSlpaXaVd9MjYmHh4esVMM88fDwwOvXr/Hbb7+pbR8xYgTMzc2ZUqlrC15hNMuXL8fBgwdx4sQJte1t2rSBi4uLxvATbdkCgF9//RXh4eHYvXu32vbevXujdu3amD59ep62PrZTFhkZidq1a+PNmzfM74mKisLgwYNx8+ZNuLu753CkWMNeeIcK8nbMsnLu3DlMmTIFV69exZgxYzBlyhRZIb0ODg5o3bo1nJycJGG8LhEdHQ1/f3/4+/vjwYMHaNq0KYYOHYrevXvLyniYkpKC0NBQhISE4NSpU7h06RLev3+PKlWqSE6Vo6OjrMUdXpor3gXMea7+Zp+IakpcwToR5akLyT5xzI7cFXgnJycmrY+m8Tk748aNw8mTJ3HixIkcfXz27Bnatm0LJycnLFu2LE9bvPVbPMMOgZzpyhcsWJCvpDCAbuvyeC4EzJw5E/7+/jh8+HAOZ/Pvv/9Gly5d8MMPP2D27NlMfcteZDkhIQFmZmaSE0NEeP36NdPvIXsxaXWFh3UlTLCwIRwpHUJTJpuEhARcuXIFO3fuxJ49e5hDQk6fPs30upYtW+b5mho1amDt2rUaB+nQ0FAMGzZMqmGTF7x3uHiG0TRs2BA///yzxvf88ccfmD17Ni5duvRRbQFAnTp1sGTJErRu3Vpt+4kTJ+Dh4YFr167laYunU8bC9u3bsXDhQly/fp3p9evXr8fEiRPRpk0brFu3rsA1eXiGCvJ2zICMG7enpyeOHDmCH374Ab/88ku+wnAGDRqEkJAQREVFwdjYGE2aNIGTkxNatWqFhg0bykoUwTNxBQB06NABx48fR8mSJfHDDz9gyJAhOZIK5Jd3797h/PnzOHXqFIKDg3H58mV8+PBBdvptoOCaq+LFiyMkJAQ1a9ZU2x4eHg4HBwfmek3aXP0taJggT12IUqlEjRo1NKZnT01Nxa1bt5i/5/jx4zW2vXnzBtu3b5cVNhsfH49GjRohNjYW/fv3V9m13L59O6ysrHDhwgWm64W3Ropn2GHWdOVz587VqVpNkZGRqFSpErfQeJ4LAe/evUPr1q1x8eJFtG3bVkWycPz4cTRs2BAnT57MsWOoCU1zwuwMHDgwz9focphgoYdvfV+BNlmyZAk1adKE+fVZq5NnVsTO/mCt2G1iYkJRUVEa26OiosjExIS5bxMnTqRhw4ZpbHd3d6fJkycz2Tp37hwZGBhQjx49KDQ0lOLj4yk+Pp7OnTtHrq6uZGhoSOfPn2fum4WFRZ7f1cLC4qPbIsqoRp6XPVNTUyZbtWvXpuPHj2tsP378ONWpU4e5bzdu3FD7OH36NPn4+FCpUqXI19eXyVa7du3I0tKSNm/ezPz5rKxcuZL09fWpZs2aVLduXZWHHCIjI8nJyYlKly5NBw8ezHd/njx5QoMGDSJ9fX3q3r073b59O9+2svLo0SPauHEj/fDDD1ShQgVSKBRkampK7du3p4ULFzLZyDqGqHvIGUOIiLp06UIHDhyg1NTU/H4tjaSkpFBwcDB5eXlRy5YtqUiRIlSpUiXm9/v5+dHjx4+59MXIyChXW48fPyYjIyMun1VQihUrRg8fPsz3+4sUKUJPnjzR2P7kyRMqUqQIk61Zs2YxPQrChw8faNmyZVSqVCmqUqUKBQQEyHr/y5cvacSIEWRpaSndRy0tLcnd3Z3++++/AvWtIFSsWJGCgoI0tv/1119UsWJFJlsKhYJMTEyoa9eu5OLiovHBysOHDyk9PZ359bmhVCopLi5OOu7duzfFxsbm217JkiXp8uXLGtsvXbpEJUuWZLaXkpJC8+fPp9q1a5OxsTEZGxtT7dq1ad68efTu3bt897OgKBQKlf9b9t99bGysrLF85MiR9ObNG+l4+/btlJiYKB3Hx8dThw4dCtjrwoHYkSpE3Lt3D40bN8bLly+ZXl+iRAmYmppi0KBBGDBgAEqWLKn2dSwFQUuWLIl9+/Zp3L06ffq0lH6cBZ47XLzDaExNTREcHCylT8/OlStX4OjoyBSixtMWkJHt78iRIxq1FRcuXED79u2l7IB59e3WrVsas+g9efIENWrUYN6VyMwWp25IKVmyJCZMmABPT0+mlcS2bdti06ZN+RZGa4JXqGBWCqrhMjExgUKhwJgxY9CsWTONryuoaDcyMhJ+fn5YuXIlEhMTmVYeeSau4M379+9x4cIFBAcH4+TJk7h48SIqVqyIli1bomXLlnBwcGDSM2XCU3PFs7wDkJEIY/ny5QUqYKyJgu5I8daFaJNt27bBy8sLycnJmDFjBoYPH55rceLcIB1LHsQz7JB3uvLsYWV9+vTBihUrZGuqgbx3VuTCO0HExyQmJgbe3t7w9fXN87W8d6REqOD/EAV5CxEpKSk5sknlRkxMDPbv3w8/Pz8sXLgQHTt2xNChQ9G+fXvZg36jRo2wdetWjY7Uli1bclTdzo1Hjx7lmga7XLlyzILdCxcu5KrNGj16tKyJXvXq1XH8+HGNzs/Ro0c1ZpXSpi0gI67+wIEDGh2p/fv3ayywmx09PT1ER0drPA/R0dHMdcGAjHOqDjMzM1kaHwA4duyYrNezkDVU8NatWwUOFQQyHLN9+/bB0tIS3bp1y9ekLPMGvWjRIixatEjta/IbthUVFYXg4GDp8ezZMzRu3Jj59+Do6Cj7M3ODp+jc3NwcX331Fbp06YLRo0djx44dsmpQZSchIUFFc7V9+/Z8a654FzDfvHkz5s+frxVHqqD07dsXEyZMgK2trVpdiIeHh6yi47kRHh6O+vXry042ceTIEUyZMgWPHj2Ch4cHJkyYIEuPpw6FQiFNIvMDb/3WzJkz8eeff+Kbb77RGHbo5eXFZMvf35/pdaxkX1z7888/MW/ePK6fkV8qVqyIS5cuaXSkMhdoPhW3bt3CqVOnYGhoiN69e8PCwgIvXryAt7c31q5dK8uB9PLykkpYvH//Ht7e3tJC+tu3b2X1K/s5/ZL3ZIQjVYjYuHGjrOrnhoaG6NOnD/r06YMnT57A398fY8aMQUpKCgYOHIhffvmFeeKXmejC3NxcbU0qf39/HD16lLlvxsbGePz4scZJ/OPHj5mTRCQnJ+eq0TA3N5e1mjRkyBBMmDAB1atXR+fOnVXaDh06BG9vbyxduvSj2wKAMWPGoG/fvihXrhxGjhwp6V3S0tKwevVq+Pj4MKcX5+mUAeB6s+GdWax9+/a4dOkSfH19uU3qeDlmLMUU5bBlyxbJcXrx4gWaNm0KBwcHDBs2TEqPzArvxBXZd781JTpgoXbt2rh27RpOnz4NpVIJpVIJR0fHfOvVihQpIjlMs2bNyqG52rx5M7PmauzYsQgNDUXnzp01lncYN24cc994TlKyJ65IT0/HiRMnVGrvAew7oFOnTsXx48dRp04djboQOU5jbhCRLM3bpUuX4OnpiQsXLmDEiBGSPi+/8HR+cruXZ9VvsWJpaYmLFy9i2rRp2LFjh0rNwn79+uWrZqEuolAocpyDguwG8lwI0JQwLDusUUUHDx5Ez549pWt+4cKFWL9+PXr37o1vv/0W+/fvR/v27ZlstWzZUmVXuGnTpoiMjMzxGoF8RGifDqGp+OyrV69w9epV3Lt3D6dPn9a4u8FCpuA+JCQEz58/lzWw8qxJ1alTJ5QtWxbr169X2+7m5obo6GimcDzeYTQA0L9/f2zfvh12dnaSGD4iIgL37t1D7969ERAQ8ElsAcD06dMxb948mJqaSqtRkZGRSExMxKRJkzB//nwmO3v37kXfvn2lc5fdKZs4cSK2b9+Onj17Mtlr2bIlDh48CAsLCwAZN4H8Fh/lnVmMd6hgpmO2bNkybo4ZL5RKJSpUqIApU6Zg6NChBXJ+eCauUEdBw3ISExNx9uxZydm5du0aqlatCkdHRzg4OMDBwSHfuwbv37/H+fPncfLkSQQHB+PixYsoW7ZsjslHbvAq76BUKnH//v08nXWWpB/aSFzx/v17+Pj4qP2uPOvR3bhxA/Xq1WPum1KphLGxMYYPHy6ljFbHTz/9xGSPd/KK7KSmpmLVqlXSTsGvv/6ar1IgBQ075L2QlT0bo6mpKcLDw3M9J5pQKpXo0KGDdE0dOnQIrVq1yrHDyNo3ngkieCaHADKSVTVr1gy//vorNmzYIC3K+vn5Madk1xYiecX/EI6UDuHk5KT2eTMzM9ja2mLkyJH5GnhSUlKwd+9e+Pn54fz58+jUqROGDBnCvJKRFR41qQDg1KlTaNu2LcaNG6d2h2v58uU4evQoWrVqlactHx8fzJkzB1u3blUbRjNw4EBMmzZNo6OqiV27dmH79u24f/++9F379euH3r17y7LD2xaQsdK6bds2lfPQr18/WeGVAD+nDMg5sGaPmS4IulaAlKdjln2HQBOsOwRr165FcHAwQkJC8O7dOzRv3lxyLL799tt8rd4+fvwYJ0+eREhICIKDg/H06VMUK1YMzZo1Q6tWrTBp0iTZNgH+5/XNmzc4c+YMjh07hk2bNiExMZF5B4O35oonmfpDTRCnwsi6jlxHytrammkHSY5znB1ezg9P/VZB4Z2unKfzo41U6h9rIUAu5ubmuHLlCqpUqYK0tDQUKVIER44cQZs2bfJl7/Xr1yhWrFiOxZT09HQkJibKKnWiVCoxfPhwKVRw1apV6N+/v0qo4Pr16z/7MQkQjtRnzaVLl7Bp0ybs2LED1tbWGDx4MPr3768z2/u8drjS09PRp08f7N27V2MYze7du2Xpfb4keDllvEXAWSmoLd4rrDzRZmrr27dvS85PcHAwUlJS0KxZMzg5OcHDwyM/3QWQv8QV6uB1jaSnp+Py5csIDg7GqVOncO7cOSQlJaFixYoatXvZMTY2ljRXDg4OaNGiRb41V6mpqdLEJ5O4uDisXbsWSUlJ6NKli6yaPEqlEnv37s1z7GbRvmkzcUVBySuxTWbaeF2ZnPFwfnjpt3hrrniiy3WkPgaRkZFITk6Gvb29rHkIz3vq/v374enpievXr0vOTyZJSUmoV68eFi9ezFwWxNHRkWlR7tSpU7L7WtgQjtRnTGaIz8CBA3MNB2RZ6eZZkyorvHa4AH5hNDxrXPGul5XJ5cuXVb6rra0tvvvuO421XD4GuuxI8Q4V1GXHTBPR0dFYvXp1vp2f3BJXsIrYs1OQ83rp0iWpL2fPnkViYiLKlSsHR0dHSetkbW3NbK9x48a4du0abG1tpR28/GquBg8eDENDQymT6Js3b1C9enW8e/cOZcqUwe3btxEYGJhjB10T2X9bBSF7tq2CwlMXUlh23ng4P9n1W9OnTy+Qfotn2CHvWk0fm2fPnnG7vuWQmcDh6tWraNy4MaZMmYL+/ftLNahsbW3x559/Mo9LSqUSmzdvlnZ5ClKI29nZGb1794abm5vadj8/P+zcuRNBQUFMfRP8D+FI6RBDhgzJ8zUKhQIbN25kssdzpTvrDU7TJaMLNzgeeHh44PXr1/jtt9/Uto8YMQLm5ua5ZgrUhq1MJk+ejMWLF6NYsWLSBPThw4d4+/YtPDw8ZNkC+DllPAf97PAOAdM1x0wbPHv2TNIOBQcH4969ezAwMEDjxo3h5OTElOpdU+IKBwcH2YkrgJxhjAW5RpRKJaysrFRSlX/zzTey+pMdXpqrqlWrwtfXF87OzgAywl7mzp2L27dvw9zcHJ6enrh06RLzam1ejlRERAS6du0q/YYLYksuPHUhISEhTLZYs0527NgRAQEB0pg0f/58jBgxQtJx/vfff2jRogVu377NZI+n88Nbv6WO/IYd8kxXzgqr82NiYoKoqChJb9WpUyds2LABZcqUASBfm8NzIWDixInYunUrunXrhpMnT6JGjRq4e/cufvnlFyiVSvz666+oWbMmtm3bxtQ3nnO4smXL4vTp06hSpYra9gcPHqBly5aIjo5m6hvAN1SwMCMcKR3CxcVFY1taWhqOHz9eICFrQeBZkwrgu8PFe9eHZ40rnraAjEnLiBEjsGjRIri7u0sT2Q8fPmDNmjXw9PTEunXrmBMg8HTKeA76PCfc6tAlx4z3bu+oUaMQHByMu3fvQl9fHw0bNpR2aZo2bcokms6EZ+KKTHt5wXqN3L17V0reoi3yq7kqWrQobt68KU2QXV1dUa5cOaxYsQJARsilo6Mjnj17xtSPSpUqISwsTOPumBztEM/EFboO71o3PJ0fbeu3ChJ2yDu6gKfzw5LkoEyZMszZUHkuBFSsWBFr1qxBx44dce/ePdjZ2eHw4cPo0KEDgIyFgu+//x7//PMP02fyxNjYGNeuXYOdnZ3a9jt37qBevXpITk5mssc7VLBQo916vwIeHDhwgKpVq0YWFhY0b968T9KHlJQU2rFjBzk7O5OxsTH16NGD/vzzz3xXK1coFKRUKkmpVErV4bM/WKtsT5w4kYYNG6ax3d3dnSZPnszcNxMTE4qKitLYHhUVRSYmJh/dFhFRgwYNaOnSpRrblyxZQg0aNGCy5e/vT0ZGRrRy5Up6//699Pz79+9p+fLlZGRkRJs3b2buG080XRP5uT7Ukb2qe0EpiD2evwUiosaNG9PUqVPp6NGjlJSUlK8+ZbJmzRrq06cPWVlZkYWFBXXu3JkWL15Mly9fzvdvvzCQlpZGFy5coPnz51O7du2oWLFipFAoyNramun9xYsXp1u3bknHZcqUod9//106fvjwIRkbG3Pr7/Xr15mvkazXm7pHQX9bmTx8+JBu3rxJaWlpzO/58OEDvXv3TuW52NhYmjVrFk2aNInOnDkjqw8KhYLi4uKk4+y/09jYWFnftWLFimRtbZ3ro1KlSrL6yJu//vqLateuTWZmZjR79mxKTEyUbSOv/xtve7GxsaRQKLjZ4nH95gd9fX36559/pGMjIyO6d++edBwdHU16enqfomtkZ2dHW7du1di+ZcsWsrW1ZbbXtm1bWr9+vcb2jRs3krOzs6w+FlaEI6XDnD17lpo3b04mJiY0efJkevnypaz3BwYGMj3kEhUVRb/88gtVrlyZvv76a5o2bRp9+PBBlo3ixYtTxYoVaebMmfTgwQNKSEhQ+2ChevXqud5gz507R9WqVWPuW4kSJSgkJERje0hICJUoUeKj2yLKcMxyu6E9fPiQ2THj6ZQVNnTJkeL5W9Amt27dotWrV1Pv3r3pq6++InNzc+rYsSMtWrRItq13797la4KXFQsLC7K0tMzzwcrFixdpwYIF1KFDBzI1NSWFQkHly5enAQMGkJ+fHz169IjZVqtWrWjKlClERHT69GlSKpUUHR0ttR89epS++eYbZnt5IdeR2rdvHwUHB+f6YCUlJYW8vLyoc+fONGfOHEpNTaW+fftKjpm9vT3z/27QoEE0fPhw6fj169dUvnx5KlWqFNWqVYv09fXp8OHDzH3T5Uk3by5evEiOjo5kZGRE48aNo+fPn+fbllKppGfPnknHxYoVo8jIyHzb43kePtY5zc9CAO++jRw5kt68eSMdb9++XWXcjI+Ppw4dOjDZmjZtGlWoUIFiY2NztMXExFCFChVo2rRpzH0rU6YM3b9/X2P7/fv3qUyZMsz2CjPCkdJBbt26RZ07dyZ9fX0aMmQIPX36NF92tL2qHxkZSU5OTqRUKum///6T9V6eO1y8d306duxIbm5uGtuHDh3KPHjxtEVEZGpqSnfu3NHYHhERQaampky2eDplRHwHfd5kXzwwMTGh3377rcCLCpkUxJHivdv7Mc7Dv//+S9OnTyczMzNZY8izZ8+offv2pK+vT0qlkho1apTrzTg3/P39mR6sKBQKKlOmDPXr14/Wr19PDx48yFe/iIiCg4PJ2NiYKleuTMbGxjRkyBCV9pEjR9IPP/yQb/vZketIZZ3sFZQJEyZQqVKlyM3NjSpXrkxdu3YlW1tb2rFjB+3atYtq1qxJ/fr1Y7JlY2NDQUFB0rGvry+VLVtWWkiYPHkyOTo6MvctL4fgUzpSHTp0UFkgmTdvHsXHx0vHL168IHt7e2Z7CoWCTExMaNy4cbR8+XKND1ZbHTt2JBcXF3JxcSF9fX1ydnaWjjMfcvrGy8HIfk5NTU0LdE55LgQoFArasmWLxvvM5s2bZfVNqVSq/N9MTU3z/X97/fo1Va9enUxNTWnkyJG0bNkyWrZsGY0YMYJMTU3J3t6eXr9+zdw3IyOjXOcit2/fJiMjI2Z7hRnhSOkQT548oUGDBpG+vj51796dbt++/am7lIN3797Rtm3bqHXr1mRiYkK9evWiv/76q0A2C7rDxXvX5+TJk6Snp0cTJ05UWb2JjY2lCRMmkJ6eHp04ceKj2yIicnBwoBkzZmhsnz59Ojk4ODDZ4umUEfEd9Hk7A7wXFbTlmPHY7eV5HjKJi4ujHTt20IgRI8jOzo6USiUVKVKEHBwcaNasWcx2Bg8eTFZWVjR37lxaunQp2draypoYa5OIiAiu9m7fvk3Lli2jHTt25FjVXrduHV27do3ZVl67b6amptwcqTt37pCNjQ1z3ypUqCDtEt29e5cUCgX9+eefUntwcDB9/fXXTLZMTExUJsUuLi70448/Sse3bt2iUqVKMfctL4egY8eOsn4LPJ0f3r9TnmGHgwYNYnqwwtP5USgUKr8HhUJB5ubm0rGFhYWs/xvPhQDe9xneO1wJCQk0cuRIKl68uNQfS0tLGjVqlOyIJ96hgoUZkWxChzAxMYFCocCYMWPQrFkzja/Lr8C+IHyMmlSPHj3C0KFDERISgufPnzPb7tSpE8qWLYv169erbXdzc0N0dDT+/PNP5r7wqnHF29Yff/yB7t27Y8KECZg4caKUfCE2NhZLlizBsmXLsH//fnTu3DlPW46OjmjRogV+/fVXte0zZszA2bNnERwczNQ3npXOeYvEeaPN2k9A/n8LmX3jdR54Jq4AgPLly2PDhg1o164dAOD+/fuwt7dHUlJSvoteEhGuXLmCx48fQ6FQoFKlSqhbt26hTd2sDp6CeJ6JKwDAwMAAjx8/xtdffw0gQ9QeHh4OGxsbAEBMTAzKly/PlKSjRIkSOHPmDKpVqwYgI9PYokWL8P333wPISMtdo0YNvH37lqlvvOsX8RyXeP5OdR2lUglzc3PpN5mQkAAzMzNpHCUivH79mum78vwtALqdIEIb10hycjJSU1Px7t07EBESExNx8OBBVKtWTcoyysL06dPx+++/49KlSzmSQMXGxqJRo0bo378/vL29mW0WVj5N2WyBWt69ewcAWLRoERYtWqT2NXImZ6NGjcLChQtRrFgxAEBAQAC6du0q1btISEhAv379mByMxo0bo0KFCvjpp5+kmlRnz57N8Tq5Tl5KSgr27t0LPz8/nD9/Hp06dcLhw4dlTRw9PDzQtm1bmJubY9KkSdKPOi4uDgsXLoS/vz+OHj0qq1/u7u7o3LkzlxpXPG117twZPj4+8PDwwJIlS6Qsia9evYK+vj4WL17M5EQBGf+37t27IyUlJVen7FOQfX1H19Z7WDNCyYHHb4E3165dQ/fu3eHk5IRmzZrlyM4kl+joaNSuXVs6trGxQZEiRRATEyOr5lMmp06dwtChQxEVFSVdI5nOlJ+fn6y6djzTIPMcewH2SSELrAWKWUlLS1PJ5qivrw89PT3pWKlUMv9+69Spg61bt2LevHk4c+YM4uLi0KpVK6n94cOHKFu2LHPfeJcf0PVx6WMip1YTz/PA87cAqI5JVatWRZEiRVRShFetWhWxsbFcP/NT0q1bN7i6umLEiBFISEhA06ZNYWBggBcvXmDp0qXMC7tTpkxBYGAgbGxs0L9/fymDakREBLZt24Zy5cphypQp2vwqusMn2QcTfBR4hg7w3rK+ePEijRgxgiwsLKhOnTq0fPly2TqrrKxdu5aKFClCSqVS2vbPDD9avXp1vu3qKk+fPqWlS5fSyJEjaeTIkeTj40NPnjyRbWfFihVkaGhISqVSCo1QKpVkaGhIy5Ytk2VLlwXFuqzf4v1b0GWBffYQH6KcYT6s3L9/n0xMTMjJyYkOHDhAERERdOfOHdq7dy85ODhQ0aJFZenWeGqutBFeSUT09u1bCgwMpEWLFtGiRYvo4MGD9PbtW9l2ckOO3oqIry7kY2vL5KJNrU9B9Vs8ww6NjY1V+taxY0eVZCm6nKQjOjqaRo8ezfx6nudUGyHp7u7uNH78eBo/fjwZGhrSkCFDpGN3d3fZ56FEiRJ08+ZNIiJav3491apVi9LS0mjXrl1kZ2cnyxbPUMHCjAjt+4zR5dCBzPo0AwcOlHa41CFnh+vff//lsuvDczWZ98q0Nvjnn3+we/du3L9/H0DGClyPHj1Qvnx5WXaUSiWGDx8u7VqsWrUK/fv3l3bN3r59i/Xr13+SsBfeoYI8zyvv3wLP88D7+s0e4pNpI2uYD8C26zNmzBjcuXMHJ06cyNFGRGjTpg2qVauGlStXMvWNJ9oYew8ePAg3Nze8ePFC5fmSJUti48aN3Oq1yA3t4x3meufOHRw9ehRWVlbo1auXiv3ffvsNDRs2RJ06dZhsxcTEwNfXVwovat68uUpYoJ6eHg4cOCCFJeaFnp4eYmNjpXpIpqamCA8Pl2pKyQ3t69ChgxTSeujQIbRq1Ur6baWkpODIkSOfZIzjXaspL2JiYuDt7Q1fX1+m19+6dQunTp2CoaEhevfuDQsLC7x48QLe3t5Yu3YtKleuzFybMa9C8gkJCRg8ePAnCUl3dHRk2iVnLewNZEhIIiIiUKFCBfTu3RvVq1fHzJkz8fTpU9ja2jKHzWbCK1SwMCMcKR1CG5MWXXak8qIgGpOCwHMw1OUJPG94Dvo8nYFMe7rqmPH+LfA8D7yvX576hho1amDevHkaHYhDhw5h6tSpuHnzJtNnZkIcNFe8r7fQ0FA4Ojqia9eumDhxIuzt7QFkFPZdsmQJ/vjjD4SEhKBx48Z52sorhDE1NRVJSUmfhTbn559/xn///YfVq1cDyDgPQ4YMkcJl//rrLzRv3hyLFy9mssfT+eGt3+J5zWlj7sDL+Tl48CB69uwpae4qV66M9evXo3fv3vj2228xbtw4tG/fnrlfPMdfXZ5zZVKrVi24ubnBxcUFNWrUwJEjR9CkSRNcuXIFnTp1kh3G6OzsrBIqaGdnl69QwcKM0EjpEOvWrcOsWbOkSbK7uzsaNWok/QhTUlIQFBT0Sfp28OBBptexrprz1JicPn2a6XWseonsawsFWWvgaQvge43wdspYk1Kw0LJlS9y9e1c6btq0KSIjI3O85lPB87zy1lvxPA+8r1+e+oYnT56gZs2aGttr1KiBqKgoWTZ5aq54MmfOHAwePBjr1q1Teb5p06Zo2rQp3N3dMXv2bKbf6rJly7TUy4LDe0z6448/sGLFCpXnxo4dK42XjRs3xoQJE5gdqezXb//+/XO85ocffmCyxVu/pctkd34WLlyo4vzs37+f2fmZM2cORo8ejV9//RUbNmzAhAkT8NNPP+HPP/9EgwYNZPdNG3pXnrx+/RrFihXL4fClp6cjMTERZmZmsux5eXmhX79+GD9+PFq3bo0mTZoAAI4ePYq6devK7t/Vq1fh4+MDANizZw9Kly6Na9euYe/evfDy8voiHCmhkdIheGsbeMbXarsmVUHI/GylUqlzKUe1cU55xujz1nG8evVKbQHDtLQ0evXqlSxbPNHl86ANeJ0HbX1PHlqfvNJ4y+0bT80Vb22DpaUlhYeHa2y/ceMGWVhYMNvjCU9dCO8xycLCQqUOo4uLi0oZikePHpGxsTGzPV2Gp+aKd62mBg0a0Lhx4+jNmzfk4+NDCoWCatSoQZcuXWK2kYmZmZlUey41NZX09PTo2LFjsu1oA97j5b59+8jGxoaSkpJytCUmJlLVqlXp4MGDsvsZExNDV69eVblHXLx4MddyKJowNjaW6nj26tVLKofx5MmTz+a3lRdiR+ozhueqPu9VG547XJaWljA1NcWgQYMwYMAAlCxZsqDd+yIgzrsN+/fvh6enJ65fv54ju1tycjIaNGiAxYsXM2s5tLESl9mv9+/fw9vbWyVU8FPBexWe93ngDU+tz+3btzWGomS3nxfLli1D48aNc2iu7Ozs4OLigjZt2sDHx4dJc8V7RzU5OTnX693c3FzK+irH5rFjx3Dv3j0AgK2tLdq0aQNjY2NZdnjukvMekz58+IDnz59LOtl9+/aptMfHxzOFdmkD3votIsKgQYOksMN3795hxIgRKmGHrND/a4wzQ0ATExNRt25dlXTlcrh79y62b9+OYsWK4ccff4SHhwd8fHzytYP05s0b6begp6cHY2Nj6VrLD7zHX573mTVr1mDy5Mlqs6UWLVoUnp6e8PX1lT2WW1lZwcrKSuW5hg0byrKRSZUqVXDgwAG4uLggKCgI48ePB5CR1VHuPbqwIhypzxieIT686d69e56vYY1LjomJwf79++Hn54eFCxeiY8eOGDp0KNq3b5/vWjI8B0NdncDzhuegz9sZ0EaoIK/zyjukl/fNl+f1Gxoaip49e2rU+vTs2ZNZ6wMArVu3VjupUygUICJZv//g4GDMmzdPbZtCocC4ceMwdepUZls8sbGxwcmTJzXqak6cOCHVbWKBpzPL2/nhia2tLUJDQzWGLJ05cwZVq1ZltsfT+Vm9ejXi4+Ol4xs3buTQb/n4+HwWYYe8nZ+goCBpDEpPT8eJEydyaCFZZQY8x1/e95mbN29K+j5Nnzdjxgxme9qAd6hgYUQkm9AheAvsAX6r+rqc5CArT548gb+/PzZv3oyUlBQMHDgQv/zyC/T12dcMeIr1eWfd0eXMeGXLlsXp06dVanBk5cGDB2jZsiWio6PztOXs7IzevXvDzc1Nbbufnx927tz5yTSDvBNr6Op54H39duzYEeXLl8+h9cnE3d0dT58+ZRpHWPVPFStWZHqdmZkZwsPDNdazevToEWrVqoU3b94w2eO5o+rj44M5c+Zg69at6Nixo0rb4cOHMXDgQEybNg0TJkzI0xbPxBWAbic5WLRoEebPn49Tp06hVq1aKm03btxA69at4enpiUmTJjHZ45m8om7dulixYgVatGih9rsGBQVhwoQJzNnndJm8MuNlwuL88E7Oo8sJIoyNjXHt2jXY2dmpbb9z5w7q1auH5OTkj9wzVWJjYxETE4PatWtL5+fSpUswMzPT2PfPCeFI6RC8Jy25reonJSWhXr16zKv6vLN3aZtHjx5h6NChCAkJwfPnzz9pUVOe6HJmPJ6DPk9nIBPeoYK84H0j1+Wbb/HixRESEqIxSUR4eDgcHBxUVuo1cfPmTdSoUYNb37Kfh+zIOQ88x14g4xrt06cP9u7dC1tbW9jb24OIcOfOHdy/fx/du3fH7t27mSaZPJ1ZgL8jxXNM+vDhA9q0aYPQ0FC0bdtWKhp69+5dHDt2DE2aNMGJEydUCgrnBk/nx9LSEn///bcUdujq6oo1a9ZIzsXjx49RrVo1nYxakJuuXJez9PIef3neZ+zt7TF9+nS1u4sAsHXrVnh7eyMiIoLZpoA/IrRPh+AdDsIzxId3+IY2drhSUlKwd+9e+Pn54fz58+jUqRMOHz6cLyeK52DI05YuZ8aztrZGWFiYxgl8WFgY8+5AfHy8lOFJHR8+fGCabGeiDd2QrjpmPM8DwPd78tT61KpVCw0aNICbmxv69u0LU1NT5n5ogpfmind4pVKpxO7du7Fz504EBARIEyc7OzvMmjULffv2Ze7bhQsXsGDBAo3to0ePhoODA7M9gF/4J+8xycDAAMeOHcPSpUuxY8cOafy0sbHBr7/+ivHjxzM7UUCGc5NZMwoA2rZtK92zgIxQwkePHjHZ4q3f4q25YklXzoquZ8bjBe/7jKurK6ZPn462bdvm2L2LjY3FjBkzNDpZgo/Ix85uIcgdnlnPypQpI2W3Ucf9+/epTJkyTLZ4Z6PhmZ3p4sWLNGLECLKwsKA6derQ8uXL6b///mPuS3Z4ZsrRRtYdXc2MN23aNKpQoYJKVqxMYmJiqEKFCjRt2jQmW3Z2drR161aN7Vu2bCFbW1vmvrVt25bWr1+vsX3jxo3k7OzMbI/neeWd4Y3neeB9/dasWZP8/Pw0tm/cuJFq1qzJZOv06dM0ePBgMjU1paJFi9IPP/xAp0+fZu5LdjKze2rK+ikn+yfPsZc3RkZG9PjxY43tjx8/JiMjI2Z7Dg4O5OjomOfjc6Bo0aJ09epVje1Xr16lokWLMtmqV68e+fr6amxfvnw51a1bl7lvM2bMoJEjR0rHxYoVo59++olmzZpFs2bNokaNGtHEiROZbAUGBpKBgYF0/X/zzTd08uRJKlmyJLVr147++usv5n7xhmeWSCK+4y/v+8zr16+pevXqZGpqSiNHjqRly5bRsmXLaMSIEWRqakr29vb0+vVrZnsC7SAcKR2C96TFyMgo13SWt2/fZr5h6nL6aIVCQRUrViQvLy8KDAzU+GCF52CoyxN4Ir5OGc9Bn6czQMR/YsvzvPKeiPI8D7yv36VLl1Lx4sXp8OHDOdr++OMPKlGiBC1ZsoTZHlHGde/n50ctW7YkhUJBNjY2NH/+fIqJiZFl5/Hjx0wPFniOvUREHz58oHfv3qk8FxsbS7NmzaJJkybJciB5OrPaQBsLRTzS7RPxdX4WLlxIxYsXpxs3buRou379OpUoUYIWLlzI3Lc6deqoXAfZ76lHjhyhatWqMdnima6cSLdT5PMcf7WxgJKQkEAjR46k4sWLS46tpaUljRo1il6+fCnLlkA7CEdKh+A9aeG5qs971Zy3I8WzxhXPwVCXJ/Da2C3jNejzXonjPbHV5R0HIn7ngff3TEtLo549e5JCoSA7OztycXGh7t27k62tLSmVSnJ1dVU7iWbl/v37NG3aNCpfvjwZGBhQly5dmN/7999/5/tzs8N7R3XQoEE0fPhw6fj169dUvnx5KlWqFNWqVYv09fXVOqfq0IYzy8v50caYFBgYSKVKlcpxTyhVqpRsWzydn/fv31PLli1JX1+fOnToQOPGjaNx48ZRhw4dSF9fn1q0aEHv379n7hvPmlm8azXxdH50uYYf7/tMJm/fvqXXr1/Ts2fPKC4ujh4+fEg+Pj4UFBRUkO4KOCEcKR2C96SF56o+71XzL2Uw1OUJPG/HPRNegz7PlTjeE1ve51Vbq/AFPQ/amhjs2LGDunXrRvb29mRvb0/dunWjgIAA2XbUkZiYSOvWraPixYvLXtxp2LAh/fbbbwUOl+G9o2pjY6Ny3nx9fals2bKUkJBARESTJ09mHn95O7M8nR/eY9K5c+fIwMCAevToQaGhoRQfH0/x8fF07tw5cnV1JUNDQzp//jyzPd7OT0pKCs2bN49q165NxsbGZGxsTLVq1aJ58+bl2IHMC55hh3ndn+Wiy0XuifiNv7zvM5m0bduW1qxZQ0QZu3elS5emcuXKkZGREa1evVq2PQFfhCOlQ/CetOhyfC3vHS6e8BwMdXkCr61dFZ6DPi+njPfElud51Vb1eh7nQVsTA20QEhJCAwcOpGLFipGZmRm5ubnJmiTz1FzxHntNTEwoMjJSOnZxcaEff/xROr516xaVKlVKVh95ObM8nR/eY1KHDh1UdvKyM3z4cFl6GiK+zg9PeIYdKhQK2rJlixQWb2JiQr/99lu+w+V12ZHiOf7yvs9kUqJECbp58yYREa1fv55q1apFaWlptGvXLrKzs5NtT8AX4UjpENqYtPBc1ee5as5zhys3XVR+Bn2eg6EuT+C1tdvAc9Dn5ZTxntjyPK/a2hnkcR54X788tT5ERP/++y95e3uTjY0NKRQKatasGfn5+anoL+TCS3PFc+wtXrw43bp1SzouU6YM/f7779Lxw4cPmcO2eMPT+eE9JllaWlJ4eLjG9hs3bpCFhQWzPW3AS7/FM+yQd7g8b0eK5yIsz/FXW4vXxsbGFBUVRUREvXr1olmzZhER0ZMnTz7Z717wP4QjpUNoazWDx6q+tlbNecB70Oc5GOryBF5buw08B32eThnPiS3P86qtnUEe54H39ctT69O+fXvS19cnKysrmjx5MkVERDD3g5WCaK6I+O2otmrViqZMmUJEGTtnSqWSoqOjpfajR4/SN998w2SLtzPL0/nRxg4+zwyFmfByfnjqt3iHHfKEp/PDW2bAe/zVRnKImjVr0vLly+nJkydkZmZGoaGhREQUFhZGpUuXzpdNAT+EI6VDaGs1g8eqvjZWzXU1jTcR38FQVyfw2nLceQ76vFfieIp2eZ1Xbe0M8joPPK9fnlqfLl260IEDByg1NVVWH+SSX80VEb8d1eDgYDI2NqbKlSuTsbExDRkyRKV95MiR9MMPPzDZ4unMEvF1fniPSdrIUMjL+eGt3yLS3bBDXU6Rr43xl3dyiN27d5OBgQEplUpq27at9PzcuXOpffv2+bIp4IdwpHQMbaxm8FjV571qo8s7XJnwHAx1cQKvLced56DPeyWOt2iXx3nV1s4gz/PA6/rVhtZHWxRUc0XEd0f19u3btGzZMtqxY0eOBah169bRtWvXmOzwdGaJ+Do/vMck3hkKeTo/2tBv8YJ3rSbe8FyE1cb4q43kEDExMXT16lWV733x4sVcnUDBx0E4UjoI79UMHqv6vFdteO5waWvQ5zkY6uIEnkh7NSp4Dfq8V+J4i3Z5nFdt7Qxmvp/HeeB1/fLU+ri4uDA95MBbc6WL2gbezixv54fnmMQ7QyFP50db+i0eYYe8azUR6W6KfG2MvyI5xJeFcKR0EN6Tbh6r+rxXbXjucGlj0CfiOxjq4gQ+E12vUcFzJY73xJbHedXl7JqZ8Lp+eWp9Bg0apPIwNDSkHj165HieFW1ornjtqPJcLNJG4greCzK8xyReGQp5Oj/a0G/xCjvU5cx4vGUG2hh/dXEBRaA9hCOlg/CedPNY1ee9asNzh0tbNal4Doa6OIHP5EuqUcE7VJDXedX16vW8vidPrU92ClrrRhuaK147qjwXi3g6s1nh6fzo6pjE0/nhrd/iGXbI+56qyynyifiPvyI5xJeFcKR0EG2sZhR0VZ/3qg3PHS5tOVI8B0NdncATfVlhCLxDBXmeV13eGeT5PXlpfbJTUEdKW/DYUeU5xmnLmeXp/PAak/7991+aOHGi2tCxhIQE8vDwULs4qAmezg9v/RbPsEPe91RdTpGfCc/xVySH+LIQjpQOoqurGTxXbXjucGnLkeI5GOryBP5LC0PgGSrI87zq6io8UeGYGBTUkdKG5ooXvMc4bTizPBdkeI1JEydOpGHDhmlsd3d3p8mTJzPb4+n88NZv8Qw75F2rSZdT5GfCe/wVySG+HIQjpYPo8qSF16oNzx0u3oN+VngOhro6gddVx72wwOu86vrOII/vqc1sYAV1pHhrrniircUinvBckOE1JlWvXp3OnDmjsf3cuXNUrVo1Znu8nR8ifvotnmGHvNOV63KK/Ex0ffwV6C7CkdJRdHU1g+eqDa8dLl2uUaFNdDUzniB/fAk7gzy1PoGBgSoPExMT+u2333I8n190KVSQ52KRtpxZngsyvMYkExMT6TeljqioKDIxMZHVNyJ+zg9PtFEzixe6nCI/ky9h/BVoB+FICWTBe9VGl3UhXxK66rh/SXwJO4M8d1ayZyZT9yjILo0uOVI8F4u0leWU94IMjzGpRIkSFBISorE9JCSESpQoIbtvPOCt3+KtueJZq0mXU+Rn8iWMvwLtIBwpgSx4r9rw2uHiOegLBJ+CL2FnsDCEqGWiS44UT7R5DnRtQaZjx47k5uamsX3o0KGydt94Oj+89Vs8ww5512oi0v0U+V/C+CvQDsKREsiC96oNjx0ubQz6AsGnQNcmorzRxiT+3bt3+S6Ymxu65kjxWiwqTM5sQTl58iTp6enRxIkTVRyc2NhYmjBhAunp6dGJEyeY7fF0fnjrtzLhEXbIu1ZTJrqeIv9zH38F2kE4UgJZ8F614bHDpa1BXyAQ8IWn1ufZs2dSEV2lUkmNGjXKNcVyXmhbc1UQeC4WfUmOFBHR2rVrqUiRIqRUKsnCwoIsLS1JqVRSkSJFZE+4eTo/2tJv8UAbtZqIdDNFvkBQUPQhEMigZ8+eaN68OWJiYlC7dm3p+datW8PFxUW2vSpVquDAgQNwcXFBUFAQxo8fDwB49uwZzMzMmGzcvHkTq1ev1tjesmVLzJgxQ3bfBAIBX1q2bIm7d+9Kx02bNkVkZGSO17Dg6emJ69evY/bs2TAyMsK6deswbNgwnDp1Kl996969e47n3N3dVY4VCgXS0tLyZb8grFmzBpMnT4aJiUmOtqJFi8LT0xO+vr7o0qULkz0vLy/J1vv37+Ht7Q1zc3MAwNu3b/l1XAdwd3dH586dsWvXLjx48ABEhKpVq6Jnz54oV66cLFuPHj1ChQoVNLaXK1cOjx8/ZrJlbGyMx48fa7T3+PFjGBsbM/ctOjoaS5cuhZeXV45756tXrzBnzhx4eHigdOnSedqKj49HamqqxvYPHz4gPj6euW+ZXL16FT4+PgCAPXv2oHTp0rh27Rr27t0LLy8vjBw5ktnW27dvYWpqCgA4evQoXF1doVQq0bhxY0RFRcnum0CQX4QjJZCNlZUVrKysVJ5r2LBhvmx5eXmhX79+GD9+PFq3bo0mTZoAyBgY69aty2RDW4O+QCDgS3BwMDdbx44dg7+/P9q1awcA6Ny5M+zt7ZGSkoIiRYrItpeens6tb7zhuVjE05ktLHz99dfSIl1B4On8NGrUCFu3btX4v96yZYus++rSpUvx+vVrtQuQ5ubmePPmDZYuXYoFCxbkacva2hphYWGws7NT2x4WFoaKFSsy9y0Tns4Pj0VYgYALn3pLTCAoaFyytgr0CQQC/vDS+iiVSoqJiVF5zsTEhB49elSg/mlLc1UQeBY0/ZLgneqdZ/IK3votnmGH2qrVpIsp8gWCgiIcKUGhR1uDvkAg4AtPrY9SqaRnz56pPGdqakqRkZH56htvzRVPeC8WfSlZTnmneuft/PDUb/HUXGmrVpMupsgXCAqKgojoU++KCQQF4c2bN2jSpAmePHmC/v37w9bWFgAQERGBbdu2oVy5crh48aIUUiAQCD4Nzs7O6N27N9zc3NS2+/n5YefOnQgKCsrTllKphLm5ORQKhfRcQkICzMzMoFQqpedevnzJ1LchQ4bgr7/+wk8//SRprsqUKZNvzRVPpk+fjt9//x2XLl3KoXGJjY1Fo0aN0L9/f3h7e+dpa//+/ZK+LLvmKikpCfXq1cPixYuZ9Va6jFKpRGxsLL766isAgKmpKW7cuIHKlSsDAOLi4lC2bFlZurd169Zh7Nix+PDhA8zMzKBQKPDq1SsYGBjAx8dHls4HAP79918u+q2SJUti3759GkMFT58+DVdXV7x48YLJ3qtXrzB16lTs3LlTCo23sLDAd999hzlz5sDS0lJW/zKJjY2VNNaZv9NLly7BzMxMYyihQKDLCEdK8FmgrUFfIBDwo2zZsjh9+jSqVKmitv3Bgwdo2bIloqOj87S1efNmps8cOHAg0+vKly+PDRs2SJqr+/fvw97eHklJSfnSXPGE52IRT2dW19GGIwXwc3540qlTJ5QtWxbr169X2+7m5obo6Gj8+eefzDaTk5ORmpqKd+/egYiQmJiIgwcPolq1anB2dubVdYGgcPMJd8MEAq7wLtAnEAj4ostaH21prnjBq6CptlJb6yK6nOqdt36Ld9ghkXZqNQkEnxvKvF0tgaBw0K1bN2zbtg2lSpWCoaEhmjZtiiVLlqBbt25Ys2bNp+6eQPDFk5kNTBP5yQaWnJyMgwcPYvHixVi8eDEOHTqE5OTkfPVPT08vxzHpSNCGubk5lixZgsePHyMuLg6xsbEICwuDjY0NLl++zGznS8ty6uXlhQkTJmDChAlSqvfM45kzZ8qyNWrUKCQmJkrHAQEBSEpKko4TEhLQsWNHJlvr1q1TSTXv7u6OuLg46TglJUXWrqCTkxNWrVoFX19flC1bFpaWlihevDjKli2LVatWYeXKlWjVqhWzPSAjXXmLFi0A/C9deVRUFLZs2YIVK1bIsiUQfK6I9OeCzwaeNSoEAgF/XF1dMX36dLRt21at1mfGjBno378/s72DBw/Czc0th+6jZMmS2LhxoyydD/1/iFZWzVViYiLq1q2bL82VNujWrRtcXV0xYsQIJCQkoGnTpjAwMMCLFy+wdOlSpjFOW6mtdRHeqd7XrVuHWbNmoVixYgAynJ9GjRpJoYJynJ/sDjoPh51nzSxA1GoSCFgQjpTgs0EM+gKBbjNlyhQEBgbCxsZGo9ZnypQpTLZCQ0PRs2dPdO3aFRMnToS9vT0A4Pbt21iyZAl69uyJkJAQNG7cmMnepk2b8velPiI8Fot4O7O6DM+6ZYB2nB/e8KqZBYhaTQIBE58wrFAg4ArPGhUCgUA78NL6dOjQgYYPH66xffjw4bI0JoUBY2NjKcV1r169aNasWURE9OTJEzI2Nmayoa3U1roKz1TvPDVXvPVbvDVXRKJWk0DAgsjaJ/hs2LNnD/r164e0tDS0bt0aR48eBQDMmzcPp0+fxl9//fWJeygQCAA+2cCKFy+OkJAQ1KxZU217eHg4HBwcZOt9kpOTcezYMdy7dw8AYGtrizZt2sDY2FiWHW1Qq1YtuLm5wcXFBTVq1MCRI0fQpEkTXLlyBZ06dUJsbCyTnS8lyynvVO88swAqlUoMHz5c6teqVavQv39/mJubA8iIsFi/fj1zRkE9PT3ExMRIfTMzM8P169cLnKFQpCsXCHJHOFKCzwox6AsEuo+zs7OK1sfOzk621sfY2BgREREa9TxRUVGws7OTlXiCp+ZKG/BcLPoSUlvzTvXO0/lxdHRU0eNpgrWOmbZSvQsEgtwRjpRAIBAIPiolS5ZESEgIqlevjg0bNmDlypUqWp87d+7kaaNWrVoYP348Bg8erLbdz88Py5YtQ3h4OFOfQkND4ejoqFFz9ccff8jSXGkLXotFPJxZXYdn3TKAv/PDE+FICQSfBpFsQiAQCAQfFR6JYQYPHgwPDw+ULl06R8rpw4cPY/LkyZg2bRpzn+bMmYPBgwdj3bp1Ks83bdoUTZs2hbu7O2bPni2roKk2sLKygpWVlcpzDRs2lG3nS8hyyjvVO+/kFa9fv0axYsVUskICQHp6OhITE0VCB4GgECAcKYFAIBB8VHhkAxs7dixCQ0PRuXNn2Nrawt7eHkSEO3fu4P79++jevTvGjRvH3KcLFy5gwYIFGttHjx4NBwcHZnu6zpeQ5VQbqd55OT+56beSk5PRoEEDWfotIKNmVqatzJpZWcMOBQIBf0RBXoFAIBB8VLy8vODh4QFra2s0atQITZo0AZAxoa9bty6TDaVSid27dyMgIAC2traIiIjA3bt3YWdnh23btmHv3r05Jru5kZycnOsk2NzcHO/evWO2p+tkOrNPnz5FUFCQpIv6nFJbZ6Z6z1roNpPMVO89evRgtrd//37Ur19f7XWQ6fwcOnSIydaaNWswefLkHE4UABQtWhSenp7w9fVl7ltmzaxr167h2rVrUs2szOO7d+/KqpklEAjYEBopgUAgEHx0dC0xDG/Nla7zJWQ5ffPmDZo0aYInT55orFt28eJFaWcuL3gmr+Ct3xIIBJ8G4UgJBAKBoNCRmpqKtLQ0FClSRHouLi4Oa9euRVJSErp06YIWLVow2/Px8cGcOXOwdetWtZqrgQMHYtq0aZgwYQK37/Cp0TVnVhvwTPXO0/kxNjbGtWvXNP6f79y5g3r16snKOik0VwLBx0eE9gkEAoGg0DFs2DD89NNP0vGbN2/QoEEDrFq1CkFBQWjVqpWsxBBjx45Fq1at0LlzZ9jb28PV1RUuLi6ws7ND165d4eDgIEtzVRiwsrJC3bp1VSbeDRs2/GycKCAjJHPJkiV4/Pgx4uLiEBsbi7CwMNjY2ODy5cuybPFMXpGp39KEXP0Wz7BDgUDAjnCkBAKBQFDoOHfunIq+ZcuWLUhLS8P9+/dx48YNTJgwAYsWLWK2x1tzJdAdunXrhm3btqFUqVIwNDRE06ZNsWTJEnTr1g1r1qxhtsPT+eGt3+KtuRIIBGyI0D6BQCAQFDqKFi2KmzdvolKlSgAyJqblypXDihUrAGTUf3J0dMSzZ88+ZTcFOgCPumUAMH36dPz++++4dOkSSpcurdIWGxuLRo0aoX///vD29s7TFm/9ltBcCQSfBpH+XCAQCASFDiMjIxX9yIULF1R2oIyMjJCYmMhsj7fmSqA78Er1PmXKFAQGBsLGxkaj8zNlyhQmW6ampjh37pxa/daAAQMwZ84cZicK4F8zSyAQsCHiFAQCgUBQ6KhTpw62bt0KADhz5gzi4uLQqlUrqf3hw4coW7Yssz3emiuB7sAr1Xum89O/f3/s3LkT48ePx/jx47Fz504MGDAA586dk+X88NRv8dZcCQQCNoQjJRAIBIJCh5eXF5YvX45vvvkG7dq1w6BBg1CmTBmpff/+/WjWrBmzPd6aK4HuwKNuWSY8nR+An36Lt+ZKIBCwITRSAoFAICiU3LlzB0ePHoWVlRV69eqlkgzit99+Q8OGDVGnTh0mW0Jz9XnDM9W7s7MzXF1dMWLECCQkJMDOzg4GBgZ48eIFli5dipEjRzLb4qXf4q25EggEbAiNlEAgEAgKJfb29rC3t1fbNnz4cFm2eGuuBLqFlZUVrKysVJ5r2LBhvmxdvXoVPj4+ADIKG5cuXVrF+ZHjSPHSb/HWXAkEAjZEaJ9AIBAICh2jRo1ScWwCAgKQlJQkHSckJOQorJsbvDVXgs8XXs4PwE+/BfAPOxQIBHkjHCmBQCAQFDrWrVuHt2/fSsfu7u4q+pCUlBQEBQUx2+OtuRJ8vvB0fnjqtwB+miuBQMCGcKQEAoFAUOjILu8tqNzXwcEBV65cwU8//YRNmzZh/fr1Ku116tTB+PHjC/QZgs8Dns5Pz5498eTJE4SFheHIkSPS861bt5bCB+Vw9epVKU1/ZthhVFQUtmzZIun9BAIBP0SyCYFAIBAUOpRKJWJjY/HVV18ByNCI3LhxA5UrVwaQUQOqbNmySEtL+5TdFHym8ExewRMTExNERESgQoUK6N27N6pXr46ZM2fi6dOnsLW1VdnFFQgEBUfsSAkEAoHgi4e35krweWNlZYW6deuqZIps2LDhJ3WiAL5hhwKBIG/EjpRAIBAICh1KpRLDhw+HiYkJAGDVqlXo378/zM3NAWQkBFi/fj3zjpSenh5iYmKkHS4zMzNcv35d7HAJChV79uxBv379kJaWhtatW+Po0aMAgHnz5uH06dP4R03/uwAADDRJREFU66+/PnEPBYLPC+FICQQCgaDQ4ejoCIVCkefrTp06xWRPhAoKPhd0NexQIPgcEXWkBAKBQFDoCA4O/tRdEAh0Ep41swQCQe4IjZRAIBAICiWvX79Genp6jufT09Px+vXrT9AjgUAgEHxJiB0pgUAgEBQ69u/fD09PT1y/fl3SSWWSnJyMBg0aYPHixejSpQuzTS8vL8nW+/fv4e3traK5EggEAoEgK0IjJRAIBIJCh7OzM3r37g03Nze17X5+fti5cydzUV7emiuBQCAQfP4IR0ogEAgEhY6yZcvi9OnTqFKlitr2Bw8eoGXLloiOjv7IPRMIBALBl4LQSAkEAoGg0BEfH4/U1FSN7R8+fEB8fLwsm0JzJRAIBAI5CEdKIBAIBIUOa2trhIWFaWwPCwtDxYoVme3t378f9evXx7t373K0ZWquDh06lK++CgQCgeDzRDhSAoFAICh0uLq6Yvr06YiLi8vRFhsbixkzZqBHjx7M9tasWYPJkyfnSFwBAEWLFoWnpyd8fX0L1GeBQCAQfF4IjZRAIBAICh1v3rxBkyZN8OTJE/Tv3x+2trYAgIiICGzbtg3lypXDxYsXYWpqymRPaK4EAoFAIBeR/lwgEAgEhQ5TU1OcO3cOU6dOxc6dOyU9lIWFBQYMGIA5c+YwO1GAdjRXAoFAIPi8EaF9AoFAICiUmJubY8mSJXj8+DHi4uIQGxuLsLAw2NjY4PLly7Js8dZcCQQCgeDzRzhSAoFAICi0dOvWDdu2bUOpUqVgaGiIpk2bYsmSJejWrRvWrFnDbIe35kogEAgEnz9CIyUQCASCQkvJkiUREhKC6tWrY8OGDVi5ciWuXbuGvXv3wsvLC3fu3GGyw1tzJRAIBILPH6GREggEAkGh5e3bt5Jzc/ToUbi6ukKpVKJx48aIiopitsNbcyUQCASCzx8R2icQCASCQkuVKlVw4MABPH36FEFBQXB2dgYAPHv2DGZmZrJs8dRcCQQCgeDzRzhSAoFAICi0eHl5wcPDA9bW1mjUqBGaNGkCIGN3qm7durLt8dJcCQQCgeDzR2ikBAKBQFCoiY2NRUxMDGrXrg2lMmN98NKlSzAzM4OdnZ0sW7w0VwKBQCD4/BEaKYFAIBAUaqysrGBlZaXyXMOGDfNli5fmSiAQCASfPyK0TyAQCASC/4en5kogEAgEnzfCkRIIBAKB4P/hrbkSCAQCweeL0EgJBAKBQJAFnporgUAgEHy+CEdKIBAIBAKBQCAQCGQiQvsEAoFAIBAIBAKBQCbCkRIIBAKBQCAQCAQCmQhHSiAQCAQCgUAgEAhkIhwpgUAgEAgEAoFAIJCJcKQEAoFAUCjw9/eHQqGAQqH4qJ+b+Zn+/v5asW9tbQ2FQoFZs2Zpxb5AIBAItINwpAQCgUBQYDKdgdwewlFQT926ddGoUSOUK1fuU3dFIBAIBDLQ/9QdEAgEAkHhp27durCysgIA/PPPP/j3338BAHXq1EGRIkUAQDgKGti/f/+n7oJAIBAI8oHYkRIIBAJBgdm/fz8uXLiACxcuwM3NLcfzQUFB+Pvvv1GxYkUYGhqiXLlymDBhAt6+fati59ixY2jTpg3Mzc1hZGQEOzs7/P777zk+LzQ0FA0aNICJiQnq1auHCxcuSG2zZs2CQqGAtbU1du/eDTs7OxQtWhQtW7bE3bt3VewcPHgQzZs3R7FixWBkZIS6deti48aNeX7fmzdvwtXVFSVKlIChoSEqV66MqVOnIjk5WXpNSkoKRowYATMzM3z11Vf45ZdfMHDgQKlvmagL7YuOjsaQIUNQtmxZyf6vv/6K1NRU6TUXLlxA69atUaJECRgZGcHa2hrdu3fHw4cP8+y/QCAQCDhAAoFAIBBwZObMmQSAANCjR48oJSWF6tSpQwDIyMiIatWqRUZGRgSAWrVqRenp6UREtGvXLlIoFASAjI2NqUaNGmRmZkZjx44lIqJNmzZJdk1MTMjW1pb09fUJAFWsWJE+fPig8vn6+vpkYGBAdnZ2kt2mTZtK/dy6datkr3Tp0lSxYkXpeM6cOdLrMp/btGkTERHdvn2bihUrRgCoWLFiZG9vL9lv27at9L4JEyZI761cuTJZWFhQ0aJFpf5mkvm5M2fOJCKiFy9eUPny5QkAmZqaUq1ataTvOXjwYCIiSktLoxIlSkh9r1OnDpUqVYoA0KlTpzifUYFAIBCoQ+xICQQCgUCrBAQE4Pr16zA0NER4eDhu3Lgh7SCdPHkSJ0+eBAB4enqCiPDNN98gMjISf//9N54/f45hw4blsDl//nxERERgyZIlAICoqCg8ePBA5TWpqanYu3cv7ty5g3HjxgHI2MnK3DWaPn06AKBRo0aIiorCo0eP4OLiAgDw9vbOsVuW9bMTExNRrFgx3L59G7dv38bSpUsBZOyonTp1CklJSVi1ahUAoFevXnj48CHu3bsHQ0PDPP9fvr6+ePr0KUqXLo2HDx/ixo0b2LNnD4CMhBsPHjxAfHw8/vvvPwDAlStXcO3aNTx79gw3b95EtWrV8vwMgUAgEBQc4UgJBAKBQKtcunQJAPD+/XtUrVoVCoUCderUkdovXLiA58+f49GjRwCAwYMHS3orQ0NDVK9ePYfNAQMGAICK0xAXF6fyGnNzc3Tp0iXH6549e4Znz57hyZMnAABXV1cUKVIECoUCffv2BQAkJyfj1q1bar/P5cuXAQAtWrRA+fLlAQD9+vWT2sPCwvDw4UOkpKQAyHCkAKBUqVJwcnLS8F/6H5n/r7i4OHz11VdQKBTo3r07AICIcPHiRZQoUQJNmjQBAFSpUgU1a9bEd999h2vXrqFkyZJ5foZAIBAICo5INiEQCASCj4KhoSHq1q2b43lLS0vZtiwsLAAA+vr/u40RkdrX5PU6XcXU1FTt7pKJiQkA4MSJE9i+fTvOnTuH27dvY8+ePdixYwdiYmIwadKkj91dgUAg+OIQO1ICgUAg0CoNGjQAAKSlpWH16tVSUorg4GBMmjQJ/fr1Q6lSpVCpUiUAGeFrz549AwB8+PABt2/f5t6nr776ChUqVAAA7Nu3DykpKSAi7NixAwBgbGysdics6/c5c+YM/vnnHwDA9u3bpfb69eujSpUqMDIyAgAcOHAAAPD8+XOcOnUqz75l2tfX18eOHTuk/9exY8cwatQouLi4gIgQGhqKQYMGwc/PDxcuXMDQoUMBAKdPn5b77xAIBAJBPhCOlEAgEAi0ynfffYdatWohLS0NDRo0QI0aNWBrawsLCwv07NkTCQkJAIAFCxZAoVDgwYMHqFSpEmrVqoVSpUrht99+00q/vL29AQAXL15ExYoVUalSJSkV+fTp06Wdn+xMmTIFxYoVQ2JiIuzt7VGtWjVMmDABANC2bVs4OTnBxMQEo0aNApDhZFWpUgVVq1aVwv1yY/To0fj6668RHx8PW1tb1KlTB9988w1KlCiBgQMHAshwStu0aQNLS0tUr14dNWvWxPr16wEAtWrVKtg/RiAQCARMCEdKIBAIBFqlSJEiCAkJwU8//YTy5cvj3r17iI+PR/369eHt7Y3SpUsDyNASBQUFoVWrVtDX18e9e/dQunRp1K9fXyv96t+/PwIDA9GsWTO8efMGsbGxqFOnDjZs2CAlolCHvb09zp8/DxcXFxgaGuL+/fuwtrbGlClTEBgYKL1u7ty5cHd3h6mpKV69eoXRo0ejQ4cOADJ2vDRRqlQpXLhwAYMHD0aJEiVw69YtJCcno0WLFvDx8QEA6OnpYcSIEahUqRL+/fdfPHjwANbW1vDw8ICXlxen/5BAIBAIckNBhSVYXCAQCASCQkRcXByMjY1hZmYGAHj58iWqVauGuLg49O3bFwEBAZ+4hwKBQCAoCGJHSiAQCAQCLXD+/Hl8/fXXaNWqFTp37gwbGxvExcWhaNGimDp16qfunkAgEAgKiHCkBAKBQCDQApUqVULdunVx/fp1BAUFwcDAAL169cL58+eFjkkgEAg+A0Ron0AgEAgEAoFAIBDIROxICQQCgUAgEAgEAoFMhCMlEAgEAoFAIBAIBDIRjpRAIBAIBAKBQCAQyEQ4UgKBQCAQCAQCgUAgE+FICQQCgUAgEAgEAoFMhCMlEAgEAoFAIBAIBDIRjpRAIBAIBAKBQCAQyEQ4UgKBQCAQCAQCgUAgk/8DTpLN0YtQOmwAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ - "instance = m.create_instance(data)" + "# Active capacity by technology and year\n", + "y2020_TotActCap_CE = d_vars['vCEActCap'][d_vars['vCEActCap'].sYear=='y2020']\n", + "y2025_TotActCap_CE = d_vars['vCEActCap'][d_vars['vCEActCap'].sYear=='y2025']\n", + "y2030_TotActCap_CE = d_vars['vCEActCap'][d_vars['vCEActCap'].sYear=='y2030']\n", + "y2035_TotActCap_CE = d_vars['vCEActCap'][d_vars['vCEActCap'].sYear=='y2035']\n", + "y2040_TotActCap_CE = d_vars['vCEActCap'][d_vars['vCEActCap'].sYear=='y2040']\n", + "y2045_TotActCap_CE = d_vars['vCEActCap'][d_vars['vCEActCap'].sYear=='y2045']\n", + "y2050_TotActCap_CE = d_vars['vCEActCap'][d_vars['vCEActCap'].sYear=='y2050']\n", + "\n", + "# Avoid all the variables in sCE that begin with sPE2TE and sTE2TE\n", + "y2020_TotActCap_CE = y2020_TotActCap_CE[~y2020_TotActCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2025_TotActCap_CE = y2025_TotActCap_CE[~y2025_TotActCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2030_TotActCap_CE = y2030_TotActCap_CE[~y2030_TotActCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2035_TotActCap_CE = y2035_TotActCap_CE[~y2035_TotActCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2040_TotActCap_CE = y2040_TotActCap_CE[~y2040_TotActCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2045_TotActCap_CE = y2045_TotActCap_CE[~y2045_TotActCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2050_TotActCap_CE = y2050_TotActCap_CE[~y2050_TotActCap_CE.sCE.str.startswith('sPE2TE')]\n", + "y2020_TotActCap_CE = y2020_TotActCap_CE[~y2020_TotActCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2025_TotActCap_CE = y2025_TotActCap_CE[~y2025_TotActCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2030_TotActCap_CE = y2030_TotActCap_CE[~y2030_TotActCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2035_TotActCap_CE = y2035_TotActCap_CE[~y2035_TotActCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2040_TotActCap_CE = y2040_TotActCap_CE[~y2040_TotActCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2045_TotActCap_CE = y2045_TotActCap_CE[~y2045_TotActCap_CE.sCE.str.startswith('sTE2TE')]\n", + "y2050_TotActCap_CE = y2050_TotActCap_CE[~y2050_TotActCap_CE.sCE.str.startswith('sTE2TE')]\n", + "\n", + "# Delete the column sYear and make the index the column sCE\n", + "y2020_TotActCap_CE = y2020_TotActCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2025_TotActCap_CE = y2025_TotActCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2030_TotActCap_CE = y2030_TotActCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2035_TotActCap_CE = y2035_TotActCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2040_TotActCap_CE = y2040_TotActCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2045_TotActCap_CE = y2045_TotActCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "y2050_TotActCap_CE = y2050_TotActCap_CE.drop(columns=['sYear']).set_index('sCE')\n", + "\n", + "#graph the results in a bar chart for each technology\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "# Create a figure and a set of subplots\n", + "fig, ax = plt.subplots(1, 1, figsize=(10, 5))\n", + "\n", + "# Set the bar width\n", + "barWidth = 0.15\n", + "\n", + "# Set the position of the bars on the x-axis\n", + "r1 = np.arange(len(y2020_TotActCap_CE))\n", + "r2 = [x + barWidth for x in r1]\n", + "r3 = [x + barWidth for x in r2]\n", + "r4 = [x + barWidth for x in r3]\n", + "r5 = [x + barWidth for x in r4]\n", + "r6 = [x + barWidth for x in r5]\n", + "r7 = [x + barWidth for x in r6]\n", + "r8 = [x + barWidth for x in r7]\n", + "r9 = [x + barWidth for x in r8]\n", + "\n", + "# Make the plot\n", + "plt.bar(r1, y2020_TotActCap_CE.vCEActCap, color='b', width=barWidth, label='2020')\n", + "plt.bar(r2, y2025_TotActCap_CE.vCEActCap, color='r', width=barWidth, label='2025')\n", + "plt.bar(r3, y2030_TotActCap_CE.vCEActCap, color='g', width=barWidth, label='2030')\n", + "plt.bar(r4, y2035_TotActCap_CE.vCEActCap, color='y', width=barWidth, label='2035')\n", + "plt.bar(r5, y2040_TotActCap_CE.vCEActCap, color='c', width=barWidth, label='2040')\n", + "plt.bar(r6, y2045_TotActCap_CE.vCEActCap, color='m', width=barWidth, label='2045')\n", + "plt.bar(r7, y2050_TotActCap_CE.vCEActCap, color='k', width=barWidth, label='2050')\n", + "\n", + "# Add xticks on the middle of the group bars\n", + "plt.xlabel('Technologies', fontweight='bold')\n", + "plt.xticks([r + barWidth for r in range(len(y2020_TotActCap_CE))], y2020_TotActCap_CE.index, rotation=90)\n", + "plt.ylabel('Capacity [GW]')\n", + "plt.title('Active Capacity by Year and Technology')\n", + "# Create legend & Show graphic\n", + "plt.legend()\n", + "plt.show()" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 27, "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sCEsYearvCETotCapvCENewCapvCEDecCapvCEActCapvCEHibCapvInvCostCEvCEDeltaActCapvEmiCO2CEvEmiSOxCEvEmiPM25CE
112sCESOPHVCEWTy202022.92067910.7054793.05380022.9206790.05.0980280.00.00.00.0
113sCESOPHVCEWTy202540.35585020.4889723.05380040.3558500.06.2574000.00.00.00.0
114sCESOPHVCEWTy203052.66412815.3620783.05380052.6641280.03.0641820.00.00.00.0
115sCESOPHVCEWTy2035112.50000062.8896723.053800112.5000000.08.0327930.00.00.00.0
116sCESOPHVCEWTy2040125.00000015.5538003.053800125.0000000.01.3101820.00.00.00.0
117sCESOPHVCEWTy2045137.50000023.20547910.705479137.5000000.01.3034550.00.00.00.0
118sCESOPHVCEWTy2050150.00000032.98897220.488972150.0000000.01.2227110.00.00.00.0
\n", + "
" + ], + "text/plain": [ + " sCE sYear vCETotCap vCENewCap vCEDecCap vCEActCap \\\n", + "112 sCESOPHVCEWT y2020 22.920679 10.705479 3.053800 22.920679 \n", + "113 sCESOPHVCEWT y2025 40.355850 20.488972 3.053800 40.355850 \n", + "114 sCESOPHVCEWT y2030 52.664128 15.362078 3.053800 52.664128 \n", + "115 sCESOPHVCEWT y2035 112.500000 62.889672 3.053800 112.500000 \n", + "116 sCESOPHVCEWT y2040 125.000000 15.553800 3.053800 125.000000 \n", + "117 sCESOPHVCEWT y2045 137.500000 23.205479 10.705479 137.500000 \n", + "118 sCESOPHVCEWT y2050 150.000000 32.988972 20.488972 150.000000 \n", + "\n", + " vCEHibCap vInvCostCE vCEDeltaActCap vEmiCO2CE vEmiSOxCE vEmiPM25CE \n", + "112 0.0 5.098028 0.0 0.0 0.0 0.0 \n", + "113 0.0 6.257400 0.0 0.0 0.0 0.0 \n", + "114 0.0 3.064182 0.0 0.0 0.0 0.0 \n", + "115 0.0 8.032793 0.0 0.0 0.0 0.0 \n", + "116 0.0 1.310182 0.0 0.0 0.0 0.0 \n", + "117 0.0 1.303455 0.0 0.0 0.0 0.0 \n", + "118 0.0 1.222711 0.0 0.0 0.0 0.0 " + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "### Solve the model instance\n", + "# Lets define a dataset with the characteristics of each CE technology\n", + "# The dataset NAMED CE TECHNOLOGIES will contain the following columns:\n", + "# - sCE: Name of the technology\n", + "# - sYear: Year of the data\n", + "# - vInvCostCE: Investment cost of the technology\n", + "# - vCENewCap: New capacity of the technology\n", + "# - vCETotCap: Total capacity of the technology\n", + "# - vCEDecCap: Decomissioned capacity of the technology\n", + "# - vCEActCap: Actual capacity of the technology\n", + "# - vCEHibCap: Hibernated capacity of the technology\n", + "# - vCEDeltaActCap: Change in actual capacity of the technology\n", + "# - vEmiCO2CE: CO2 emissions of the technology\n", + "# - vEmiSOxCE: SOx emissions of the technology\n", + "# - vEmiPM25CE: PM2.5 emissions of the technology\n", "\n", - "To solve the model instance, please select a solver within the Pyomo SolverFactory. Please note that any solver has to be previously installed." + "# Create the dataset\n", + "import pandas as pd\n", + "CE_TECHNOLOGIES = pd.DataFrame(columns=['sCE', 'sYear', 'vCETotCap', 'vCENewCap', 'vCEDecCap', 'vCEActCap', 'vCEHibCap','vInvCostCE' ,'vCEDeltaActCap', 'vEmiCO2CE', 'vEmiSOxCE', 'vEmiPM25CE'])\n", + "\n", + "# Fill the dataset with the data\n", + "CE_TECHNOLOGIES['sCE'] = d_vars['vInvCostCE'].sCE\n", + "CE_TECHNOLOGIES['sYear'] = d_vars['vInvCostCE'].sYear\n", + "CE_TECHNOLOGIES['vCETotCap'] = d_vars['vCETotCap'].vCETotCap\n", + "CE_TECHNOLOGIES['vCENewCap'] = d_vars['vCENewCap'].vCENewCap\n", + "CE_TECHNOLOGIES['vCEDecCap'] = d_vars['vCEDecCap'].vCEDecCap\n", + "CE_TECHNOLOGIES['vCEActCap'] = d_vars['vCEActCap'].vCEActCap\n", + "CE_TECHNOLOGIES['vCEHibCap'] = d_vars['vCEHibCap'].vCEHibCap\n", + "CE_TECHNOLOGIES['vInvCostCE'] = d_vars['vInvCostCE'].vInvCostCE\n", + "CE_TECHNOLOGIES['vCEDeltaActCap'] = d_vars['vCEDeltaActCap'].vCEDeltaActCap\n", + "CE_TECHNOLOGIES['vEmiCO2CE'] = d_vars['vEmiCO2CE'].vEmiCO2CE\n", + "CE_TECHNOLOGIES['vEmiSOxCE'] = d_vars['vEmiSOxCE'].vEmiSOxCE\n", + "CE_TECHNOLOGIES['vEmiPM25CE'] = d_vars['vEmiPM25CE'].vEmiPM25CE\n", + "\n", + "# Lets extract the data for the technology 'sCENUCLEAR' and visualize the results\n", + "CE_TECHNOLOGIES[CE_TECHNOLOGIES['sCE']=='sCESOPHVCEWT']\n" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 19, "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "Set parameter Username\n", - "Academic license - for non-commercial use only - expires 2024-02-08\n", - "Read LP format model from file C:\\Users\\mperezb\\AppData\\Local\\Temp\\tmpmqagrw1f.pyomo.lp\n", - "Reading time = 12.22 seconds\n", - "x1: 3041283 rows, 2087907 columns, 9608393 nonzeros\n", - "Gurobi Optimizer version 10.0.1 build v10.0.1rc0 (win64)\n", - "\n", - "CPU model: Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz, instruction set [SSE2|AVX|AVX2]\n", - "Thread count: 4 physical cores, 8 logical processors, using up to 8 threads\n", - "\n", - "Optimize a model with 3041283 rows, 2087907 columns and 9608393 nonzeros\n", - "Model fingerprint: 0x37432e03\n", - "Coefficient statistics:\n", - " Matrix range [1e-06, 8e+04]\n", - " Objective range [1e+00, 1e+00]\n", - " Bounds range [1e+00, 1e+00]\n", - " RHS range [8e-02, 3e+05]\n", - "Presolve removed 2099124 rows and 1053626 columns (presolve time = 6s) ...\n", - "Presolve removed 2664369 rows and 1618871 columns (presolve time = 10s) ...\n", - "Presolve removed 2854600 rows and 1959981 columns\n", - "Presolve time: 26.53s\n", - "Presolved: 186683 rows, 128005 columns, 844726 nonzeros\n", - "\n", - "Concurrent LP optimizer: dual simplex and barrier\n", - "Showing barrier log only...\n", - "\n", - "Ordering time: 4.74s\n", - "Elapsed ordering time = 5s\n", - "Ordering time: 9.82s\n", - "\n", - "Barrier statistics:\n", - " Dense cols : 55\n", - " AA' NZ : 6.531e+06\n", - " Factor NZ : 3.652e+07 (roughly 400 MB of memory)\n", - " Factor Ops : 1.555e+10 (less than 1 second per iteration)\n", - " Threads : 3\n", - "\n", - " Objective Residual\n", - "Iter Primal Dual Primal Dual Compl Time\n", - " 0 3.59842610e+10 -1.52495545e+11 1.45e+09 1.42e-14 5.26e+07 39s\n", - " 1 2.90457839e+10 -1.49791853e+11 1.24e+09 2.68e+01 4.55e+07 40s\n", - " 2 1.80837126e+10 -1.43289176e+11 8.42e+08 4.32e+01 3.07e+07 41s\n", - " 3 8.86953119e+09 -1.42249242e+11 4.77e+08 3.98e+01 1.87e+07 42s\n", - " 4 4.50101072e+09 -1.41855111e+11 2.55e+08 2.28e+01 1.07e+07 43s\n", - " 5 3.51991446e+09 -1.35904602e+11 2.01e+08 2.04e+01 8.75e+06 44s\n", - " 6 1.60627030e+09 -1.18835722e+11 9.12e+07 1.40e+01 4.52e+06 45s\n", - " 7 9.69552808e+08 -8.37953269e+10 5.39e+07 5.09e+00 2.46e+06 45s\n", - " 8 5.92609284e+08 -6.43453229e+10 3.17e+07 3.04e+00 1.47e+06 46s\n", - " 9 5.13154565e+08 -5.22856139e+10 2.70e+07 2.08e+00 1.20e+06 47s\n", - " 10 4.01840719e+08 -4.52462652e+10 2.04e+07 1.63e+00 9.22e+05 47s\n", - " 11 3.06257118e+08 -3.21231559e+10 1.48e+07 9.10e-01 6.40e+05 48s\n", - " 12 2.35655998e+08 -2.67355733e+10 1.05e+07 6.82e-01 4.73e+05 49s\n", - " 13 2.05278451e+08 -2.33665352e+10 8.69e+06 5.58e-01 3.97e+05 50s\n", - " 14 1.47015884e+08 -1.53518238e+10 4.92e+06 2.56e-01 2.43e+05 52s\n", - " 15 1.13305544e+08 -1.19500873e+10 2.24e+06 1.64e-01 1.67e+05 53s\n", - " 16 1.03070781e+08 -1.00714939e+10 1.45e+06 1.22e-01 1.40e+05 54s\n", - " 17 8.96380085e+07 -7.33215164e+09 6.85e+05 6.81e-02 1.04e+05 55s\n", - " 18 6.22096493e+07 -5.56008172e+09 2.03e+04 4.07e-02 5.79e+04 56s\n", - " 19 4.24308490e+07 -3.76617489e+09 9.05e+03 2.05e-02 2.80e+04 57s\n", - " 20 3.68132953e+07 -2.73256976e+09 6.87e+03 1.26e-02 1.96e+04 58s\n", - " 21 2.80348303e+07 -2.30077790e+09 3.91e+03 9.78e-03 1.30e+04 60s\n", - " 22 1.89801602e+07 -1.16626361e+09 1.60e+03 3.10e-03 5.38e+03 61s\n", - " 23 1.71245400e+07 -5.47305682e+08 1.35e+03 1.02e-03 2.86e+03 62s\n", - " 24 1.44378669e+07 -4.41669161e+08 1.06e+03 7.61e-04 2.20e+03 63s\n", - " 25 9.10445471e+06 -3.11621440e+08 5.19e+02 4.70e-04 1.28e+03 64s\n", - " 26 8.03938126e+06 -1.97372125e+08 4.30e+02 2.66e-04 8.35e+02 65s\n", - " 27 5.46694938e+06 -1.47573014e+08 1.37e+03 1.83e-04 5.46e+02 66s\n", - " 28 4.12460140e+06 -8.96549874e+07 1.08e+03 9.76e-05 3.22e+02 66s\n", - " 29 3.87389464e+06 -6.76895712e+07 9.92e+02 6.91e-05 2.48e+02 67s\n", - " 30 3.37088759e+06 -5.32111181e+07 9.03e+02 5.26e-05 1.93e+02 68s\n", - " 31 2.68099480e+06 -3.88228280e+07 7.09e+02 4.55e-05 1.35e+02 69s\n", - " 32 2.13795784e+06 -1.54517608e+07 4.79e+02 6.98e-05 5.84e+01 69s\n", - " 33 1.41628731e+06 -5.87831665e+06 1.80e+02 7.89e-05 2.25e+01 70s\n", - " 34 1.03573454e+06 -3.88639997e+06 8.60e+01 8.04e-05 1.39e+01 71s\n", - " 35 8.86649542e+05 -2.19309878e+06 5.37e+01 8.15e-05 8.21e+00 72s\n", - " 36 7.35152460e+05 -1.02602951e+06 2.71e+01 8.23e-05 4.27e+00 72s\n", - " 37 6.50520347e+05 -7.84918527e+05 1.74e+01 8.25e-05 3.30e+00 73s\n", - " 38 5.90478337e+05 -4.15602787e+05 1.01e+01 8.27e-05 2.10e+00 74s\n", - " 39 5.68187369e+05 -2.21415212e+05 7.98e+00 8.28e-05 1.52e+00 75s\n", - " 40 5.32775622e+05 -1.62127939e+05 5.10e+00 8.28e-05 1.26e+00 76s\n", - " 41 5.04139028e+05 -3.51733312e+04 3.07e+00 8.29e-05 8.48e-01 77s\n", - " 42 4.74721619e+05 5.64719736e+04 1.48e+00 8.29e-05 5.36e-01 78s\n", - " 43 4.55784037e+05 1.00306414e+05 8.93e-01 8.30e-05 3.78e-01 78s\n", - " 44 4.43451454e+05 1.30546054e+05 5.90e-01 8.30e-05 2.73e-01 79s\n", - " 45 4.42073740e+05 1.33043441e+05 5.69e-01 8.31e-05 2.64e-01 80s\n", - " 46 4.39219735e+05 1.38309213e+05 5.27e-01 8.31e-05 2.44e-01 81s\n", - " 47 4.28827718e+05 1.46129603e+05 3.80e-01 8.33e-05 2.03e-01 82s\n", - " 48 4.22269248e+05 1.59595445e+05 2.50e-01 8.37e-05 1.55e-01 82s\n", - " 49 4.13017371e+05 1.73421152e+05 4.55e-02 8.46e-05 1.02e-01 83s\n", - " 50 4.04941137e+05 1.81315359e+05 3.02e-02 8.50e-05 6.85e-02 84s\n", - " 51 4.03612467e+05 1.82408362e+05 2.82e-02 8.50e-05 6.37e-02 85s\n", - " 52 3.97677165e+05 1.85714597e+05 1.91e-02 8.50e-05 4.72e-02 86s\n", - " 53 3.94409242e+05 1.86616797e+05 1.53e-02 8.49e-05 4.09e-02 87s\n", - " 54 3.89946119e+05 1.88263009e+05 1.08e-02 8.48e-05 3.18e-02 87s\n", - " 55 3.88101704e+05 1.90749157e+05 9.23e-03 8.44e-05 2.38e-02 88s\n", - " 56 3.84225788e+05 1.92549252e+05 6.45e-03 8.41e-05 1.59e-02 89s\n", - " 57 3.81650039e+05 1.93635743e+05 5.03e-03 8.39e-05 1.13e-02 90s\n", - " 58 3.78896266e+05 1.94426128e+05 3.76e-03 8.36e-05 7.84e-03 91s\n", - " 59 3.75205188e+05 1.94775926e+05 2.42e-03 8.35e-05 5.41e-03 91s\n", - " 60 3.72467204e+05 1.94999664e+05 1.74e-03 8.34e-05 4.11e-03 92s\n", - " 61 3.70701694e+05 1.95223714e+05 1.41e-03 8.33e-05 3.16e-03 93s\n", - " 62 3.68699155e+05 1.95375983e+05 1.11e-03 8.32e-05 2.41e-03 94s\n", - " 63 3.66226083e+05 1.95479197e+05 8.14e-04 8.32e-05 1.79e-03 95s\n", - " 64 3.63015051e+05 1.95547683e+05 5.26e-04 8.31e-05 1.28e-03 96s\n", - " 65 3.61242765e+05 1.95608201e+05 4.22e-04 8.31e-05 1.00e-03 97s\n", - " 66 3.57590462e+05 1.95645670e+05 2.49e-04 8.30e-05 6.99e-04 98s\n", - " 67 3.55832201e+05 1.95689293e+05 1.99e-04 8.30e-05 5.24e-04 99s\n", - " 68 3.53386353e+05 1.95729060e+05 1.44e-04 8.30e-05 3.50e-04 100s\n", - " 69 3.51607878e+05 1.95751812e+05 1.15e-04 8.30e-05 2.51e-04 101s\n", - " 70 3.50182928e+05 1.95765245e+05 9.61e-05 8.29e-05 1.89e-04 101s\n", - " 71 3.49701016e+05 1.95769744e+05 9.09e-05 8.29e-05 1.70e-04 102s\n", - " 72 3.47229213e+05 1.95774846e+05 6.52e-05 8.29e-05 1.20e-04 103s\n", - " 73 3.45598507e+05 1.95777324e+05 5.30e-05 8.29e-05 9.69e-05 104s\n", - " 74 3.43099991e+05 1.95778704e+05 3.79e-05 8.29e-05 7.25e-05 105s\n", - " 75 3.42977000e+05 1.95779953e+05 3.73e-05 8.29e-05 6.87e-05 105s\n", - " 76 3.41909988e+05 1.95780443e+05 3.28e-05 8.29e-05 6.03e-05 106s\n", - " 77 3.41676681e+05 1.95781198e+05 3.19e-05 8.29e-05 5.76e-05 107s\n", - " 78 3.39142877e+05 1.95782022e+05 2.26e-05 8.29e-05 4.27e-05 108s\n", - " 79 3.36853367e+05 1.95783274e+05 1.66e-05 8.29e-05 3.18e-05 108s\n", - " 80 3.35349757e+05 1.95784635e+05 1.37e-05 8.29e-05 2.95e-05 109s\n", - " 81 3.34255806e+05 1.95784656e+05 1.20e-05 8.29e-05 2.71e-05 110s\n", - " 82 3.31687988e+05 1.95785336e+05 8.42e-06 8.29e-05 1.96e-05 111s\n", - " 83 3.28499177e+05 1.95785795e+05 5.32e-06 8.29e-05 1.26e-05 112s\n", - " 84 3.28316717e+05 1.95785813e+05 5.21e-06 8.29e-05 1.23e-05 112s\n", - " 85 3.28220316e+05 1.95785840e+05 5.15e-06 8.29e-05 1.22e-05 113s\n", - " 86 3.27913074e+05 1.95785884e+05 4.97e-06 8.29e-05 1.18e-05 114s\n", - " 87 3.27456979e+05 1.95785958e+05 4.71e-06 8.29e-05 1.11e-05 115s\n", - " 88 3.27336335e+05 1.95786004e+05 4.64e-06 8.29e-05 1.10e-05 116s\n", - " 89 3.26808884e+05 1.95786025e+05 4.36e-06 8.29e-05 1.03e-05 116s\n", - " 90 3.26740629e+05 1.95786062e+05 4.32e-06 8.29e-05 1.02e-05 117s\n", - " 91 3.26187097e+05 1.95786072e+05 4.05e-06 8.29e-05 9.56e-06 118s\n", - " 92 3.26042222e+05 1.95786115e+05 3.98e-06 8.29e-05 9.46e-06 119s\n", - " 93 3.24992701e+05 1.95786227e+05 3.50e-06 8.29e-05 8.25e-06 120s\n", - " 94 3.24571027e+05 1.95786233e+05 3.33e-06 8.29e-05 7.83e-06 121s\n", - " 95 3.24191748e+05 1.95786251e+05 3.18e-06 8.29e-05 7.54e-06 122s\n", - " 96 3.23847077e+05 1.95786335e+05 3.05e-06 8.29e-05 7.26e-06 122s\n", - " 97 3.23323154e+05 1.95786369e+05 2.87e-06 8.29e-05 6.93e-06 123s\n", - " 98 3.22851421e+05 1.95786473e+05 2.71e-06 8.29e-05 6.56e-06 124s\n", - " 99 3.22253455e+05 1.95786489e+05 2.52e-06 8.29e-05 6.09e-06 125s\n", - " 100 3.21537165e+05 1.95786589e+05 2.31e-06 8.29e-05 5.69e-06 126s\n", - " 101 3.20907283e+05 1.95786663e+05 2.15e-06 8.29e-05 5.33e-06 127s\n", - " 102 3.17896462e+05 1.95786804e+05 1.40e-06 8.29e-05 3.64e-06 128s\n", - " 103 3.17154090e+05 1.95786932e+05 1.28e-06 8.29e-05 3.35e-06 129s\n", - " 104 3.16611679e+05 1.95786911e+05 1.20e-06 8.29e-05 3.17e-06 130s\n", - " 105 3.15478718e+05 1.95786971e+05 1.04e-06 8.29e-05 2.82e-06 131s\n", - " 106 3.14133998e+05 1.95787188e+05 8.79e-07 8.29e-05 2.38e-06 132s\n", - " 107 3.12067923e+05 1.95787292e+05 6.69e-07 8.29e-05 1.82e-06 133s\n", - " 108 3.07720501e+05 1.95787397e+05 3.33e-07 8.29e-05 1.03e-06 133s\n", - " 109 3.07200876e+05 1.95787527e+05 3.13e-07 8.29e-05 9.00e-07 134s\n", - " 110 3.06838848e+05 1.95787635e+05 3.00e-07 8.29e-05 8.19e-07 135s\n", - " 111 3.06831742e+05 1.95787632e+05 2.99e-07 8.29e-05 8.19e-07 137s\n", - " 112 3.06727540e+05 1.95787639e+05 2.96e-07 8.29e-05 8.11e-07 138s\n", - " 113 3.06499461e+05 1.95787641e+05 2.88e-07 8.29e-05 7.90e-07 139s\n", - " 114 3.05596276e+05 1.95787672e+05 2.58e-07 8.29e-05 7.21e-07 140s\n", - " 115 3.05469938e+05 1.95787686e+05 2.54e-07 8.29e-05 7.12e-07 141s\n", - " 116 3.05391706e+05 1.95787694e+05 2.52e-07 8.29e-05 7.05e-07 141s\n", - " 117 3.05036066e+05 1.95787700e+05 2.41e-07 8.29e-05 6.84e-07 142s\n", - " 118 3.04872714e+05 1.95787711e+05 2.37e-07 8.29e-05 6.72e-07 143s\n", - " 119 3.04665427e+05 1.95787716e+05 2.31e-07 8.29e-05 6.55e-07 145s\n", - " 120 3.04641945e+05 1.95787717e+05 2.30e-07 8.29e-05 6.54e-07 146s\n", - " 121 3.04176674e+05 1.95787797e+05 2.18e-07 8.29e-05 6.26e-07 147s\n", - " 122 3.03909872e+05 1.95787797e+05 2.11e-07 8.29e-05 6.06e-07 148s\n", - " 123 3.03662798e+05 1.95787828e+05 2.05e-07 8.29e-05 5.92e-07 149s\n", - " 124 3.03416254e+05 1.95787844e+05 2.00e-07 8.29e-05 5.74e-07 150s\n", - " 125 3.03402469e+05 1.95787853e+05 1.99e-07 8.29e-05 5.75e-07 151s\n", - " 126 3.03399485e+05 1.95787856e+05 1.99e-07 8.29e-05 5.73e-07 152s\n", - " 127 3.02381439e+05 1.95787881e+05 1.76e-07 8.29e-05 5.26e-07 154s\n", - " 128 3.02290211e+05 1.95787909e+05 1.75e-07 8.29e-05 5.24e-07 155s\n", - " 129 3.00991302e+05 1.95787978e+05 2.21e-07 8.29e-05 4.54e-07 156s\n", - " 130 3.00984617e+05 1.95787979e+05 2.21e-07 8.29e-05 4.54e-07 158s\n", - " 131 3.00422220e+05 1.95788010e+05 2.22e-07 8.29e-05 4.27e-07 159s\n", - " 132 3.00333404e+05 1.95788032e+05 2.20e-07 8.29e-05 4.22e-07 160s\n", - " 133 3.00051546e+05 1.95788071e+05 2.12e-07 8.29e-05 4.07e-07 161s\n", - " 134 2.99963969e+05 1.95788078e+05 2.11e-07 8.29e-05 4.03e-07 162s\n", - " 135 2.99957805e+05 1.95788079e+05 2.11e-07 8.29e-05 4.03e-07 163s\n", - " 136 2.99661094e+05 1.95788142e+05 2.05e-07 8.29e-05 3.87e-07 164s\n", - " 137 2.99056346e+05 1.95788146e+05 2.04e-07 8.29e-05 3.67e-07 164s\n", - " 138 2.98766427e+05 1.95788149e+05 1.96e-07 8.29e-05 3.58e-07 165s\n", - " 139 2.98095710e+05 1.95788185e+05 1.81e-07 8.29e-05 3.36e-07 166s\n", - " 140 2.97711437e+05 1.95788194e+05 1.72e-07 8.29e-05 3.22e-07 167s\n", - " 141 2.97673481e+05 1.95788203e+05 1.71e-07 8.29e-05 3.20e-07 168s\n", - " 142 2.95824634e+05 1.95788282e+05 1.40e-07 8.29e-05 2.62e-07 169s\n", - " 143 2.95641605e+05 1.95788309e+05 1.38e-07 8.29e-05 2.58e-07 170s\n", - " 144 2.94739659e+05 1.95788396e+05 1.22e-07 8.29e-05 2.34e-07 171s\n", - " 145 2.92384211e+05 1.95788401e+05 8.93e-08 8.29e-05 1.87e-07 172s\n", - " 146 2.91887750e+05 1.95788443e+05 8.43e-08 8.29e-05 1.78e-07 173s\n", - " 147 2.90916596e+05 1.95788457e+05 8.16e-08 8.29e-05 1.62e-07 174s\n", - " 148 2.90908294e+05 1.95788457e+05 8.14e-08 8.29e-05 1.61e-07 175s\n", - " 149 2.90845941e+05 1.95788461e+05 8.10e-08 8.29e-05 1.60e-07 176s\n", - " 150 2.90820331e+05 1.95788461e+05 8.05e-08 8.29e-05 1.60e-07 178s\n", - " 151 2.90706214e+05 1.95788466e+05 8.04e-08 8.29e-05 1.62e-07 179s\n", - " 152 2.90436116e+05 1.95788484e+05 8.40e-08 8.29e-05 1.56e-07 180s\n", - " 153 2.90373181e+05 1.95788484e+05 8.61e-08 8.29e-05 1.55e-07 181s\n", - " 154 2.89880355e+05 1.95788499e+05 8.36e-08 8.29e-05 1.48e-07 182s\n", - " 155 2.88870631e+05 1.95788522e+05 6.50e-08 8.29e-05 1.35e-07 182s\n", - " 156 2.88863753e+05 1.95788527e+05 6.49e-08 8.29e-05 1.35e-07 184s\n", - " 157 2.88859277e+05 1.95788528e+05 6.49e-08 8.29e-05 1.35e-07 185s\n", - " 158 2.87879098e+05 1.95788642e+05 6.19e-08 8.29e-05 1.20e-07 186s\n", - " 159 2.87556581e+05 1.95788658e+05 5.86e-08 8.29e-05 1.16e-07 187s\n", - " 160 2.86359437e+05 1.95788673e+05 1.15e-07 8.29e-05 1.03e-07 189s\n", - " 161 2.85935359e+05 1.95788694e+05 1.56e-07 8.29e-05 9.83e-08 190s\n", - " 162 2.84892177e+05 1.95788696e+05 1.39e-07 8.29e-05 8.98e-08 191s\n", - " 163 2.84068578e+05 1.95788743e+05 3.17e-07 8.29e-05 8.10e-08 192s\n", - " 164 2.84063071e+05 1.95788743e+05 3.17e-07 8.29e-05 8.09e-08 193s\n", - " 165 2.84010956e+05 1.95788745e+05 3.17e-07 8.29e-05 8.04e-08 194s\n", - " 166 2.83910106e+05 1.95788745e+05 3.13e-07 8.29e-05 8.00e-08 196s\n", - " 167 2.82861199e+05 1.95788754e+05 3.80e-07 8.29e-05 7.42e-08 197s\n", - " 168 2.82289560e+05 1.95788780e+05 3.36e-07 8.29e-05 6.84e-08 198s\n", - " 169 2.81862770e+05 1.95788787e+05 3.14e-07 8.29e-05 6.53e-08 199s\n", - " 170 2.79824315e+05 1.95788830e+05 1.91e-07 8.29e-05 5.33e-08 200s\n", - " 171 2.78484173e+05 1.95788871e+05 1.65e-07 8.29e-05 4.57e-08 201s\n", - " 172 2.78475365e+05 1.95788875e+05 1.65e-07 8.29e-05 4.55e-08 202s\n", - " 173 2.78356482e+05 1.95788899e+05 1.62e-07 8.29e-05 4.44e-08 203s\n", - " 174 2.78152601e+05 1.95788925e+05 1.58e-07 8.29e-05 4.26e-08 204s\n", - " 175 2.78126600e+05 1.95789003e+05 1.57e-07 8.29e-05 6.82e-08 205s\n", - " 176 2.77639033e+05 1.95789203e+05 1.48e-07 8.29e-05 1.01e-07 206s\n", - "\n", - "Barrier performed 176 iterations in 206.11 seconds (125.81 work units)\n", - "Numerical trouble encountered\n", - "\n", - "Model may be infeasible or unbounded. Consider using the\n", - "homogeneous algorithm (through parameter 'BarHomogeneous')\n", - "\n", - "\n", - "Solved with dual simplex\n", - "Extra simplex iterations after uncrush: 12\n", - "Iteration Objective Primal Inf. Dual Inf. Time\n", - " 160670 1.9582328e+05 0.000000e+00 0.000000e+00 259s\n", - "\n", - "Solved in 160670 iterations and 258.54 seconds (162.90 work units)\n", - "Optimal objective 1.958232821e+05\n" - ] + "data": { + "image/png": "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du2Qk5MDV1dXREVFYfv27ejTp4/BKktERERERFQdqN2177fffkNISIi0vGnTJhQWFuLixYs4efIkIiIisGjRIoNUkoiIiIiIqDpRO5H6999/0bRpU2l5//79CAkJgVKpBACMGDECZ8+e1X8NiYiIiIiIqhm1EylLS0s8fPhQWj58+DA6dOigsv3+/fv6rR0REREREVE1pHYi1bp1a3z11VcAgF9//RXp6eno0aOHtP3y5cuoX7++/mtIREREZCQymeqDiKiY2oNNzJo1C71798bmzZtx48YNjBw5Eq6urtL2rVu3wt/f3yCVJCIiIiIiqk7UTqS6deuGY8eO4ZdffoGLiwtefPFFle2tW7dG+/bt9V5BIiIiIiKi6kbtRGr06NFYunQpJk2aVO72MWPG6K1SRERERERE1Zna90h9+eWXKoNNEBERERERPanUTqSEEIasBxERERERUY2hdtc+ALh37x4sLS0rLaNQKHSqEBERERERUXWnUSLVrFmzCrcJISCTyVBYWKhzpYiIiIiIiKozjRKpH374Afb29oaqCxERERERUY2gUSLl7+8PJycnQ9WFiIiIiIioRlB7sAkiIiIiIiJ6RO1EysPDAyYmJoasCxERERERUY2gdte+lJQUQ9aDiIiIiIioxlA7kXrmmWfUKnf8+HGtK0NERERERFQTqJ1IDRgwwJD1ICIiIiIiqjHUTqRmz55tyHoQERERERHVGBy1j4iIiIiISENqt0h1794dMpms0jIymQz79+/XuVJERERERETVmdqJVOvWrSvcdu/ePURHRyM3N1cfdSIiIiIiIjWVbOsQwnj1eNKonUhFRUWVWVdQUICVK1fiww8/RIMGDTBv3jy9Vo6IiIiIiKg60voeqW+++QbNmzfHxx9/jDlz5uD8+fMYMmSIRjEWLFiAdu3awdbWFk5OThg4cCCSk5NVyuTk5CAsLAz16tWDjY0NQkJCkJ6erlImNTUVffv2hbW1NZycnDBlyhQUFBRoe2hERERERESV0jiR2rNnD1q3bo3x48dj5MiRuHjxIsaPHw9TU7UbtySJiYkICwvD4cOHERsbi/z8fAQFBSE7O1sqEx4ejp07dyImJgaJiYm4fv06Bg0aJG0vLCxE3759kZeXh0OHDuHLL7/Exo0bMWvWLI3rQ0REREREpA6ZEOr1pPz9998xdepUHD58GGPHjsWMGTPg4OCg18rcunULTk5OSExMRNeuXZGZmQlHR0dER0dj8ODBAIALFy7A29sbSUlJ6NixI37++Wf069cP169fh7OzMwBgzZo1mDp1Km7dugVzc/PH7jcrKwtKpRKZmZlQKBR6PSYiIkNR6ROPUoMBsZM8kV6UHmfrSf5oJcgSpP93R3eVbWp+nSQD4T1S+qVubqB2M1LHjh1hZWWFsWPHwtPTE9HR0eWWe+uttzSv7f/LzMwEANjb2wMAjh07hvz8fAQGBkplvLy84O7uLiVSSUlJ8PX1lZIoAAgODsa4ceNw9uxZtGnTpsx+cnNzVQbGyMrK0rrORERERET05FE7kXJ3d4dMJsO2bdsqLCOTybROpIqKijB58mT4+/vDx8cHAJCWlgZzc3PY2dmplHV2dkZaWppUpmQSVby9eFt5FixYgPfff1+rehIREREREamdSF25csWA1QDCwsJw5swZHDx40KD7AYDIyEhERERIy1lZWXBzczP4fomIiIiIqHbQfIQIA5gwYQJ27dqFAwcOoGHDhtJ6FxcX5OXlISMjQ6VVKj09HS4uLlKZ33//XSVe8ah+xWVKs7CwgIWFhZ6PgoiIiIiInhRqJ1IlW3BKUiqVaNasGQYNGqRxciKEwMSJE7F161YkJCTA09NTZXvbtm1hZmaG/fv3IyQkBACQnJyM1NRU+Pn5AQD8/Pzw4Ycf4ubNm3BycgIAxMbGQqFQoEWLFhrVh4iIiIiISB1qJ1J//vlnueszMjJw6dIlzJw5E3FxcXB3d1d752FhYYiOjsb27dtha2sr3dOkVCphZWUFpVKJ0NBQREREwN7eHgqFAhMnToSfnx86duwIAAgKCkKLFi3w2muvYeHChUhLS8N7772HsLAwtjoREREREZFBqD38eWWysrIwbNgw2NraVjiaX7k7Lz2m6P/bsGEDRo4cCeDRhLxvv/02vv32W+Tm5iI4OBirVq1S6bZ39epVjBs3DgkJCahTpw5GjBiBjz76SO25rTj8ORHVRBz+nMjwOPz5/3D48+qLw5/rl7q5gV4SKeDRPFMvvvgirl69qo9wVYqJFBHVREykiAyPidT/MJGqvphI6Ze6uYFcXzt0cHDAnTt39BWOiIiIiIio2tJbInX48GE0btxYX+GIiIiIiIiqLbUHmzh16lS56zMzM3Hs2DHMnz8fs2fP1lvFiIiIiIiIqiu1E6nWrVtDJpOV2wfWwcEBERERGD9+vF4rR0REREREVB2pnUilpKSUu16hUKBu3bp6qxAREREREVF1p3Yi5eHhYch6EBERERER1Rh6G2yCiIiIiIjoScFEioiIiIiISENMpIiIiIiIiDSkdiJ14MABFBQUGLIuRERERERENYLaiVT37t1x584dQ9aFiIiIiIioRlA7kSpv/igiIiIiIqInkUb3SMlkMkPVg4iIiIiIqMZQex4pABg5ciQsLCwqLfPjjz/qVCEiIiIiIqLqTqNEytbWFlZWVoaqCxERERERUY2gUSK1bNkyODk5GaouRERERERENYLa90jx/igiIiIiIqJHOGofERERERGRhtROpOLj42Fvb2/IuhAREREREdUIaidS5ubm2LNnj8q6TZs2wdPTE05OThgzZgxyc3P1XkEiIiIiIqLqRu1Eau7cuTh79qy0fPr0aYSGhiIwMBDTpk3Dzp07sWDBAoNUkoiIiIiIqDpRO5E6ceIEevbsKS1/99136NChA7744gtERERg2bJl2Lx5s0EqSUREREREVJ2onUjdvXsXzs7O0nJiYiJ69+4tLbdr1w7Xrl3Tb+2IiIiIiIiqIbUTKWdnZ6SkpAAA8vLycPz4cXTs2FHafu/ePZiZmem/hkRERERERNWM2olUnz59MG3aNPz666+IjIyEtbU1unTpIm0/deoUGjdubJBKEhERERERVSem6hacN28eBg0ahG7dusHGxgZffvklzM3Npe3r169HUFCQQSpJRERERERUnaidSDk4OODAgQPIzMyEjY0NTExMVLbHxMTAxsZG7xUkIiIiIiKqbtROpIoplcpy13OyXiIiIiIielKofY8UERERERERPcJEioiIiIiISENMpIiIiIiIiDTERIqIiIiIiEhDTKSIiIiIiIg0pPGofURERERU+8kSElSW441TDaJqiy1SREREREREGmIiRUREREREpCEmUkRERERERBpiIkVERERERKQhoyZSBw4cQP/+/VG/fn3IZDJs27ZNZfvIkSMhk8lUHs8995xKmTt37mDYsGFQKBSws7NDaGgo7t+/X4VHQURERERETxqjJlLZ2dl4+umnsXLlygrLPPfcc7hx44b0+Pbbb1W2Dxs2DGfPnkVsbCx27dqFAwcOYMyYMYauOhERERERPcGMOvx579690bt370rLWFhYwMXFpdxt58+fx549e3D06FE8++yzAIDly5ejT58++OSTT1C/fv1yn5ebm4vc3FxpOSsrS8sjICIiIiKiJ1G1v0cqISEBTk5OaN68OcaNG4fbt29L25KSkmBnZyclUQAQGBgIuVyOI0eOVBhzwYIFUCqV0sPNzc2gx0BERERERLVLtU6knnvuOWzatAn79+/Hxx9/jMTERPTu3RuFhYUAgLS0NDg5Oak8x9TUFPb29khLS6swbmRkJDIzM6XHtWvXDHocRERERERUuxi1a9/jDBkyRPq/r68vWrVqhcaNGyMhIQE9e/bUOq6FhQUsLCz0UUUiIiIiInoCVesWqdKeeuopODg44NKlSwAAFxcX3Lx5U6VMQUEB7ty5U+F9VURERERERLqqUYnUP//8g9u3b8PV1RUA4Ofnh4yMDBw7dkwqExcXh6KiInTo0MFY1SQiIiIiolrOqF377t+/L7UuAUBKSgpOnDgBe3t72Nvb4/3330dISAhcXFxw+fJlvPvuu2jSpAmCg4MBAN7e3njuuefwxhtvYM2aNcjPz8eECRMwZMiQCkfsIyIiIiIi0pVRW6T++OMPtGnTBm3atAEAREREoE2bNpg1axZMTExw6tQpPP/882jWrBlCQ0PRtm1b/Prrryr3N33zzTfw8vJCz5490adPH3Tu3Bmff/65sQ6JqFYrPUE2ERER0ZPKqC1SAQEBEEJUuH3v3r2PjWFvb4/o6Gh9VouIiIiofCV/RKrkOwwR1X416h4pIiIiIiKi6oCJFBERERERkYaYSBEREREREWmIiRQREREREZGGmEgRERERERFpiIkUERERERGRhphIERERERERaYiJFBERERERkYaYSBEREREREWmIiRQREREREZGGTI1dASIiIiIi0hOZTHVZCOPU4wnAFikiIiIiIiINMZEiIiIiIiLSEBMpIiIiIiIiDTGRIiIiIiIi0hATKSIiIiIiIg0xkSIiIiIiItIQEykiIiIiIiINMZEiIiIiIiLSECfkJSKqhWTvq07IKGZzQkYiIiJ9YosUERERERGRhtgiRUSVSpAlGLsKRERERNUOW6SIiIiIiIg0xESKiIiIiIhIQ0ykiIiIiIiINMREioiIiIiISENMpIiIiIiIiDTERIqIiIiIiEhDTKSIiIiIiIg0xESKiIiIiIhIQ0ykiIiIiIiINMREioiIiIiISENMpIiIiIiIiDTERIqIiIiIiEhDTKSIiIiIiIg0xESKiIiIiIhIQ0ykiIiIiIiINGTUROrAgQPo378/6tevD5lMhm3btqlsF0Jg1qxZcHV1hZWVFQIDA3Hx4kWVMnfu3MGwYcOgUChgZ2eH0NBQ3L9/vwqPgoiIiIiInjRGTaSys7Px9NNPY+XKleVuX7hwIZYtW4Y1a9bgyJEjqFOnDoKDg5GTkyOVGTZsGM6ePYvY2Fjs2rULBw4cwJgxY6rqEIiIiIiI6Alkasyd9+7dG7179y53mxACS5YswXvvvYcBAwYAADZt2gRnZ2ds27YNQ4YMwfnz57Fnzx4cPXoUzz77LABg+fLl6NOnDz755BPUr1+/yo6FiIiIiIieHNX2HqmUlBSkpaUhMDBQWqdUKtGhQwckJSUBAJKSkmBnZyclUQAQGBgIuVyOI0eOVBg7NzcXWVlZKg8iIiIiIiJ1VdtEKi0tDQDg7Oysst7Z2VnalpaWBicnJ5XtpqamsLe3l8qUZ8GCBVAqldLDzc1Nz7UnIiIiIqLarNomUoYUGRmJzMxM6XHt2jVjV4mIiIiIiGqQaptIubi4AADS09NV1qenp0vbXFxccPPmTZXtBQUFuHPnjlSmPBYWFlAoFCoPIiIiIiIidVXbRMrT0xMuLi7Yv3+/tC4rKwtHjhyBn58fAMDPzw8ZGRk4duyYVCYuLg5FRUXo0KFDldeZiIiIiIieDEYdte/+/fu4dOmStJySkoITJ07A3t4e7u7umDx5Mj744AM0bdoUnp6emDlzJurXr4+BAwcCALy9vfHcc8/hjTfewJo1a5Cfn48JEyZgyJAhHLGPiIiIiIgMxqiJ1B9//IHu3btLyxEREQCAESNGYOPGjXj33XeRnZ2NMWPGICMjA507d8aePXtgaWkpPeebb77BhAkT0LNnT8jlcoSEhGDZsmVVfixERERERPTkkAkhhLErYWxZWVlQKpXIzMzk/VJEpSTIEqT/d0d3lW28fBiXTPa//wvIVLfNUS0rZvO1ItKGTPWjpfpZq2XXwIQE1YPtjniV5fjuJbfx70F1Utnfg9r2Pq0K6uYG1fYeKSIiIiIiouqKiRQREREREZGGmEgRERERERFpiIkUERERERGRhow6ah8RVT+yhASV5fjyixERERE90dgiRUREREREpCEmUkRERERERBpiIkVERERERKQhJlJEREREREQaYiJFRERERESkIY7aR0RERGQkMpnqshDGqQcRaY4tUkRERERERBpiIkVERERERKQhJlJEREREREQaYiJFRERERESkISZSREREREREGmIiRUREREREpCEmUkRERERERBpiIkVERERERKQhTshLREREpAXZ+6qz6YrZnE2X6EnCFikiIiIiIiINMZEiIiIiIiLSEBMpIiIiIiIiDTGRIiIiIiIi0hAHmyAiIiIiqqU4KIrhsEWKiIiIiIhIQ0ykiIiIiIiINMREioiIiIiISENMpIiIiIiIiDTERIqIiIiIiEhDTKSIiIiIiIg0xOHPiZ5wCQmyUmvijVIPIiKi2khW6s+s4OjjtQZbpIiIiIiIiDTEFikiIiIiompIlpCgsiwCAoxSDyofW6SIiIiIiIg0xBYpIiIiouqi5A01vJmGqFpjIkVEREREVFU4+kStUa279s2ZMwcymUzl4eXlJW3PyclBWFgY6tWrBxsbG4SEhCA9Pd2INSZ6sshkZf8eEBER6VPx3xr+zaHqptq3SLVs2RL79u2Tlk1N/1fl8PBw7N69GzExMVAqlZgwYQIGDRqE3377zRhVJSIiIiLSGqckqVmqfSJlamoKFxeXMuszMzOxbt06REdHo0ePHgCADRs2wNvbG4cPH0bHjh2ruqpETy52UyAiIqInTLXu2gcAFy9eRP369fHUU09h2LBhSE1NBQAcO3YM+fn5CAwMlMp6eXnB3d0dSUlJlcbMzc1FVlaWyoOIiIjoSSN7XyY9iEgz1TqR6tChAzZu3Ig9e/Zg9erVSElJQZcuXXDv3j2kpaXB3NwcdnZ2Ks9xdnZGWlpapXEXLFgApVIpPdzc3Ax4FEREREREVNtU6659vXv3lv7fqlUrdOjQAR4eHti8eTOsrKy0jhsZGYmIiAhpOSsrq1olU+wlRURERERUvVXrFqnS7Ozs0KxZM1y6dAkuLi7Iy8tDRkaGSpn09PRy76kqycLCAgqFQuVBRERERESkrhqVSN2/fx+XL1+Gq6sr2rZtCzMzM+zfv1/anpycjNTUVPj5+RmxlkREREREVNtV665977zzDvr37w8PDw9cv34ds2fPhomJCYYOHQqlUonQ0FBERETA3t4eCoUCEydOhJ+fH0fsIzKy0jcti9nsn0pERES1S7VOpP755x8MHToUt2/fhqOjIzp37ozDhw/D0dERABAVFQW5XI6QkBDk5uYiODgYq1atMnKtiYiIiIiotqvWidR3331X6XZLS0usXLkSK1eurKIaERERERERVfNEioiI9CMh4X/dLQMC2NWSiKgmSpAlSP8PEAFGqwc9wkSK6AlU8h6m+G5GrAgRERFRDcVEiqgWkZWahExwEjIiIiIig2AiRVSDlWziJyIiopqHvURqrho1jxQREREREVF1wESKiIiIiIhIQ0ykiIiIiIiINMR7pIhqGFlCgvT/eONVg4iIaqJSgxJhjlFqQVQrMJEiIiIiopqjZDLI0WnJiNi1j4iIiIiISENMpIiIiIiIiDTErn01AZuwqYZLSPjfezgggO9hopL3OgJAfHfV7QEioMrqQtVXyfmFAEDM5vWTqDphixQREREREZGGmEgRPQlkMtUHEVVrMplMetREJetfU4+BiOhxmEgRERERERFpiPdIEREREdVSpRsEeZcVkf4wkSKq5koO1PAIp+ElqolUP8v8HNdGHFiH6MnCrn1EREREREQaYosUEREREVENU3YgF/VaQdlyqj9skSIiIiKD4oChRFQbsUWKqBYr/uLC35uIiIiI9IstUkRERERERBpiixTpXZmhVg3QHFJyH4aOb6h9EJFh8XNMRESGxESKiIieDMysiIhIj5hIEREREVGNJHtf9QcSMZs/kFDVYSJVw/CCUfuVfo3juxmpIkRERERUISZST5CS8w0IdmkhIiI9SZAlGLsKRERVjokUkToMPbrFE0SWkKCyLAICjFIPIjIC3qdGRLUIE6lajL8QEhER1R4JCaqJaEAAE1EiY2IiVYuU/qU/3jjVKMvQv0DyF04ijajbKljbP1ol70c0xP2mvN+RiKh244S8REREREREGmKLVA2n2sxfbdqgiKiGkpVuhkIta4YiIiLSEyZSTyiOnaA9gwxBX/IFmaN7OCJN8H5Kqsn494yIjIWJFBER1WilE8Hu6F6qBL9dExGR/jGRoir/Oa+qb/DmpMVEelKNfvovOWAGOzXXXIb+e0BEZEhMpIjIqEq2JgSIAKPVg55sHFa6lqjtQ03SY/GzTFWJiRQREVV7pb8cVct2qNJf4ucYpRZERFRFak0itXLlSixatAhpaWl4+umnsXz5crRv397Y1apx2C1OcyW/4PGXL3pS8FpBVDl152vT1z4MEV8Txb8jsBGw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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ - "solver = pyo.SolverFactory('gurobi')\n", + "# vTotalCapST\n", + "y2020_TotCap_ST = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2020') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSOTH_RES'))].groupby('sST').sum().vSTTotCap\n", + "y2025_TotCap_ST = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2025') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSOTH_RES'))].groupby('sST').sum().vSTTotCap\n", + "y2030_TotCap_ST = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2030') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSOTH_RES'))].groupby('sST').sum().vSTTotCap\n", + "y2035_TotCap_ST = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2035') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSOTH_RES'))].groupby('sST').sum().vSTTotCap\n", + "y2040_TotCap_ST = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2040') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSOTH_RES'))].groupby('sST').sum().vSTTotCap\n", + "y2045_TotCap_ST = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2045') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSOTH_RES'))].groupby('sST').sum().vSTTotCap\n", + "y2050_TotCap_ST = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2050') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSOTH_RES'))].groupby('sST').sum().vSTTotCap\n", "\n", - "solver_results = solver.solve(instance, keepfiles=False, tee=True)" + "# Graph the results in a bar chart for each technology\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# Create a figure and a set of subplots\n", + "fig, ax = plt.subplots(1, 1, figsize=(10, 5))\n", + "\n", + "# Set the bar width\n", + "barWidth = 0.15\n", + "\n", + "# Set the position of the bars on the x-axis\n", + "r1 = np.arange(len(y2020_TotCap_ST))\n", + "r2 = [x + barWidth for x in r1]\n", + "r3 = [x + barWidth for x in r2]\n", + "r4 = [x + barWidth for x in r3]\n", + "r5 = [x + barWidth for x in r4]\n", + "r6 = [x + barWidth for x in r5]\n", + "r7 = [x + barWidth for x in r6]\n", + "r8 = [x + barWidth for x in r7]\n", + "r9 = [x + barWidth for x in r8]\n", + "\n", + "# Make the plot\n", + "plt.bar(r1, y2020_TotCap_ST, color='b', width=barWidth, label='2020')\n", + "plt.bar(r2, y2025_TotCap_ST, color='r', width=barWidth, label='2025')\n", + "plt.bar(r3, y2030_TotCap_ST, color='g', width=barWidth, label='2030')\n", + "plt.bar(r4, y2035_TotCap_ST, color='y', width=barWidth, label='2035')\n", + "plt.bar(r5, y2040_TotCap_ST, color='c', width=barWidth, label='2040')\n", + "plt.bar(r6, y2045_TotCap_ST, color='m', width=barWidth, label='2045')\n", + "plt.bar(r7, y2050_TotCap_ST, color='k', width=barWidth, label='2050')\n", + "\n", + "# Add xticks on the middle of the group bars\n", + "plt.xlabel('Technologies', fontweight='bold')\n", + "plt.xticks([r + barWidth for r in range(len(y2020_TotCap_ST))], y2020_TotCap_ST.index, rotation=90)\n", + "plt.ylabel('ST UNITS')\n", + "plt.title('Total Capacity by Technology and Year')\n", + "# Create legend & Show graphic\n", + "plt.legend()\n", + "plt.show()" ] }, { - "attachments": {}, - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 42, "metadata": {}, + "outputs": [], "source": [ - "### **Results**" + "# Lets define a dataset with the characteristics of each CE technology\n", + "# The dataset NAMED CE TECHNOLOGIES will contain the following columns:\n", + "# - sTE: Name of the technology\n", + "# - sYear: Year of the data\n", + "# - vInvCostST: Investment cost of the technology\n", + "# - vSTNewCap: New capacity of the technology\n", + "# - vSTTotCap: Total capacity of the technology\n", + "# - vSTDecCap: Decomissioned capacity of the technology\n", + "# - vEmiCO2ST: CO2 emissions of the technology\n", + "# - vEmiSOxST: SOx emissions of the technology\n", + "# - vEmiPM25ST: PM2.5 emissions of the technology\n", + "\n", + "# # Create the dataset\n", + "# import pandas as pd\n", + "ST_TECHNOLOGIES = pd.DataFrame(columns=['sST', 'sYear', 'vSTTotCap', 'vSTNewCap', 'vSTDecCap', 'vInvCostST' , 'vEmiCO2ST', 'vEmiSOxST', 'vEmiPM25ST'])\n", + "\n", + "# # Fill the dataset with the data\n", + "# ST_TECHNOLOGIES['sST'] = pd.DataFrame(d_vars['vSTTotCap'][d_vars['vSTTotCap'].sST.str.startswith('sST_DSOTH_RES')].groupby('sST').sum().vSTTotCap).index\n", + "# ST_TECHNOLOGIES['sYear'] = d_vars['vInvCostST'].sYear\n", + "ST_TECHNOLOGIES = pd.DataFrame(d_vars['vSTTotCap'][d_vars['vSTTotCap'].sST.str.startswith('sST_DSOTH_RES')].groupby('sST').sum().vSTTotCap)\n", + "# ST_TECHNOLOGIES['vSTNewCap'] = d_vars['vSTNewCap'].vSTNewCap\n", + "# ST_TECHNOLOGIES['vSTDecCap'] = d_vars['vSTDecCap'].vSTDecCap\n", + "# ST_TECHNOLOGIES['vInvCostST'] = d_vars['vInvCostST'].vInvCostST\n", + "# ST_TECHNOLOGIES['vEmiCO2ST'] = d_vars['vEmiCO2ST'].vEmiCO2ST\n", + "# ST_TECHNOLOGIES['vEmiSOxST'] = d_vars['vEmiSOxST'].vEmiSOxST\n", + "# ST_TECHNOLOGIES['vEmiPM25ST'] = d_vars['vEmiPM25ST'].vEmiPM25ST\n", + "\n", + "\n", + "# # Lets extract the data for the technology 'sCENUCLEAR' and visualize the results\n", + "# ST_TECHNOLOGIES[ST_TECHNOLOGIES['sST']=='sST_DSOTH_RES_DIEB']" ] }, { - "attachments": {}, - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 32, "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "sST\n", + "sST_DSOTH_RESCOOK_ELECONV 101.411742\n", + "sST_DSOTH_RESCOOK_ELEHEFF 66.007425\n", + "sST_DSOTH_RESCOOK_LPG 41.188034\n", + "sST_DSOTH_RESCOOK_NGAS 46.450856\n", + "sST_DSOTH_RESDIWA_CONV 73.116421\n", + "sST_DSOTH_RESDIWA_HEFF 107.298655\n", + "sST_DSOTH_RESFRID_CONV 619.191385\n", + "sST_DSOTH_RESFRID_HEFF 4.768800\n", + "sST_DSOTH_RESLIGH_FLUO 0.065644\n", + "sST_DSOTH_RESLIGH_INCA 1.085651\n", + "sST_DSOTH_RESLIGH_LED 3.078137\n", + "sST_DSOTH_RESOEAP_CONV 815.806139\n", + "sST_DSOTH_RESOVEN_CONV 24.698961\n", + "sST_DSOTH_RESOVEN_HEFF 24.095402\n", + "sST_DSOTH_RESWAMA_CONV 109.831829\n", + "sST_DSOTH_RESWAMA_HEFF 70.583248\n", + "sST_DSOTH_RES_ACCOP2 5.184970\n", + "sST_DSOTH_RES_ACCOP6 1.241065\n", + "sST_DSOTH_RES_BIOMF 50.206309\n", + "sST_DSOTH_RES_DIEB 18.876373\n", + "sST_DSOTH_RES_ELEC 470.967501\n", + "sST_DSOTH_RES_HPCOP3 171.245986\n", + "sST_DSOTH_RES_HPCOP6 702.233629\n", + "sST_DSOTH_RES_LPGB_COND 9.109665\n", + "sST_DSOTH_RES_LPGB_CONV 113.258236\n", + "sST_DSOTH_RES_LPGB_LOWT 0.000000\n", + "sST_DSOTH_RES_NGAB_COND 229.694554\n", + "sST_DSOTH_RES_NGAB_CONV 433.071151\n", + "sST_DSOTH_RES_NGAB_LOWT 0.000000\n", + "Name: vSTTotCap, dtype: float64" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "Extract information on variables through the model output to .csv files" + "pd.DataFrame(d_vars['vSTTotCap'][d_vars['vSTTotCap'].sST.str.startswith('sST_DSOTH_RES')].groupby('sST').sum().vSTTotCap).vSTTotCap" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 33, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "sST\n", + "sST_DSIND_CHE 23.406534\n", + "sST_DSIND_CON 7.000000\n", + "sST_DSIND_FBT 7.000000\n", + "sST_DSIND_IIS 24.120053\n", + "sST_DSIND_MAC 7.000000\n", + " ... \n", + "sST_DSTRA_RAIL_INTER 15.550739\n", + "sST_DSTRA_RAIL_URBAN 56.787067\n", + "sST_DSTRA_SEAF_SHIPDIE 0.054046\n", + "sST_DSTRA_SEA_SHIPDIE 0.007481\n", + "sST_DSTRA_SEA_SHIPFOI 0.112212\n", + "Name: vSTTotCap, Length: 87, dtype: float64" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "path = \"../data/input/openMASTER_Data.xlsx\"\n", - "output_path = \"../data/tmp/output\"\n", - "sheetname = \"Output\"\n", + "d_vars['vSTTotCap'].groupby('sST').sum().vSTTotCap" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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a9eGjY0N3nvvPZw/fx779u1Dfn6+dP9S7dq1oaOjg6ioKJw5cwZubm6oVasWoqKiMHPmTHzwwQdSwTR8+HAEBQVh3LhxmD9/PmJjY7Fq1SqsXLlS2u706dPRvXt3rFixAv369cPOnTtx7tw5adgFhUKBGTNm4JNPPkGjRo3g5OSExYsXw9bWFp6enpWXMCIiIlJbVVpUnTt3Dm5ubtJ00f1R3t7eCAwMxM8//wwAaN26tcpyx44dQ48ePaCrq4udO3ciMDAQ2dnZcHJywsyZM1XuszIxMcHhw4fh6+uLdu3awdzcHP7+/tJwCgDQuXNnhIWFYdGiRfjoo4/QqFEj7N27F82bN5di5s2bh8zMTPj4+CA1NRVdunTBwYMHoaenVxGpISIiompGIYQQVd2J10V6ejpMTEyQlpYm+6VARZBC1vWpAxFQvkOTuSjEPBRiHv6hqHmpQHl+wZiHQsxD6ZX291ut76kiIiIiqi5YVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQyqxWtqiIjKLbAGPuAcUNUdIKKS8EwVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgIN/EtVUHPSSiKhS8UwVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgDeqU83DG7SJiKgK8EwVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJgEUVERERkQxYVBERERHJoEqLqhMnTmDAgAGwtbWFQqHA3r17VdqFEPD394eNjQ309fXh7u6O69evq8Q8fPgQI0aMgLGxMUxNTTFu3DhkZGSoxFy8eBFdu3aFnp4e7OzsEBwcXKwvu3fvRuPGjaGnp4cWLVrgwIEDZe4LERERvb6qtKjKzMxEq1atsG7duhLbg4ODsXr1amzcuBFnzpyBoaEhPDw8kJWVJcWMGDECly9fRnh4OPbt24cTJ07Ax8dHak9PT0fv3r3h4OCA6OhoLF++HIGBgfj666+lmFOnTsHLywvjxo3DhQsX4Onp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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", "\n", - "d_vars_from_instance = openMASTER.export_model_to_csv(path, output_path, sheetname, instance)" + "y2020_sTEELE_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEELE')) & (d_vars['vQSTInTE'].sYear=='y2020') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2025_sTEELE_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEELE')) & (d_vars['vQSTInTE'].sYear=='y2025') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2030_sTEELE_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEELE')) & (d_vars['vQSTInTE'].sYear=='y2030') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2035_sTEELE_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEELE')) & (d_vars['vQSTInTE'].sYear=='y2035') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2040_sTEELE_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEELE')) & (d_vars['vQSTInTE'].sYear=='y2040') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2045_sTEELE_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEELE')) & (d_vars['vQSTInTE'].sYear=='y2045') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2050_sTEELE_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEELE')) & (d_vars['vQSTInTE'].sYear=='y2050') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEOPDIE_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (d_vars['vQSTInTE'].sYear=='y2020') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2025_sTEOPDIE_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (d_vars['vQSTInTE'].sYear=='y2025') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2030_sTEOPDIE_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (d_vars['vQSTInTE'].sYear=='y2030') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2035_sTEOPDIE_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (d_vars['vQSTInTE'].sYear=='y2035') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2040_sTEOPDIE_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (d_vars['vQSTInTE'].sYear=='y2040') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2045_sTEOPDIE_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (d_vars['vQSTInTE'].sYear=='y2045') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2050_sTEOPDIE_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (d_vars['vQSTInTE'].sYear=='y2050') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTENAGAS_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (d_vars['vQSTInTE'].sYear=='y2020') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2025_sTENAGAS_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (d_vars['vQSTInTE'].sYear=='y2025') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2030_sTENAGAS_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (d_vars['vQSTInTE'].sYear=='y2030') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2035_sTENAGAS_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (d_vars['vQSTInTE'].sYear=='y2035') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2040_sTENAGAS_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (d_vars['vQSTInTE'].sYear=='y2040') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2045_sTENAGAS_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (d_vars['vQSTInTE'].sYear=='y2045') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2050_sTENAGAS_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (d_vars['vQSTInTE'].sYear=='y2050') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEOLPG_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOLPG')) & (d_vars['vQSTInTE'].sYear=='y2020') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2025_sTEOLPG_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOLPG')) & (d_vars['vQSTInTE'].sYear=='y2025') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2030_sTEOLPG_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOLPG')) & (d_vars['vQSTInTE'].sYear=='y2030') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2035_sTEOLPG_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOLPG')) & (d_vars['vQSTInTE'].sYear=='y2035') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2040_sTEOLPG_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOLPG')) & (d_vars['vQSTInTE'].sYear=='y2040') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2045_sTEOLPG_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOLPG')) & (d_vars['vQSTInTE'].sYear=='y2045') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2050_sTEOLPG_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOLPG')) & (d_vars['vQSTInTE'].sYear=='y2050') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEBIOMA_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEBIOMA')) & (d_vars['vQSTInTE'].sYear=='y2020') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2025_sTEBIOMA_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEBIOMA')) & (d_vars['vQSTInTE'].sYear=='y2025') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2030_sTEBIOMA_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEBIOMA')) & (d_vars['vQSTInTE'].sYear=='y2030') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2035_sTEBIOMA_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEBIOMA')) & (d_vars['vQSTInTE'].sYear=='y2035') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2040_sTEBIOMA_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEBIOMA')) & (d_vars['vQSTInTE'].sYear=='y2040') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2045_sTEBIOMA_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEBIOMA')) & (d_vars['vQSTInTE'].sYear=='y2045') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "y2050_sTEBIOMA_RES = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEBIOMA')) & (d_vars['vQSTInTE'].sYear=='y2050') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSOTH_RES'))].vQSTInTE.sum()\n", + "\n", + "# Graph bar stackplot\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "sTEELE_RES = [y2020_sTEELE_RES, y2025_sTEELE_RES, y2030_sTEELE_RES, y2035_sTEELE_RES, y2040_sTEELE_RES, y2045_sTEELE_RES, y2050_sTEELE_RES]\n", + "sTEOPDIE_RES = [y2020_sTEOPDIE_RES, y2025_sTEOPDIE_RES, y2030_sTEOPDIE_RES, y2035_sTEOPDIE_RES, y2040_sTEOPDIE_RES, y2045_sTEOPDIE_RES, y2050_sTEOPDIE_RES]\n", + "sTENAGAS_RES = [y2020_sTENAGAS_RES, y2025_sTENAGAS_RES, y2030_sTENAGAS_RES, y2035_sTENAGAS_RES, y2040_sTENAGAS_RES, y2045_sTENAGAS_RES, y2050_sTENAGAS_RES]\n", + "sTEOLPG_RES = [y2020_sTEOLPG_RES, y2025_sTEOLPG_RES, y2030_sTEOLPG_RES, y2035_sTEOLPG_RES, y2040_sTEOLPG_RES, y2045_sTEOLPG_RES, y2050_sTEOLPG_RES]\n", + "sTEBIOMA_RES = [y2020_sTEBIOMA_RES, y2025_sTEBIOMA_RES, y2030_sTEBIOMA_RES, y2035_sTEBIOMA_RES, y2040_sTEBIOMA_RES, y2045_sTEBIOMA_RES, y2050_sTEBIOMA_RES]\n", + "\n", + "plt.bar(years, sTEELE_RES, label='Electricity', color='blue')\n", + "plt.bar(years, sTEOPDIE_RES, label='Diesel', color='red', bottom=sTEELE_RES)\n", + "plt.bar(years, sTENAGAS_RES, label='Natural Gas', color='green', bottom=[sum(x) for x in zip(sTEELE_RES, sTEOPDIE_RES)])\n", + "plt.bar(years, sTEOLPG_RES, label='LPG', color='orange', bottom=[sum(x) for x in zip(sTEELE_RES, sTEOPDIE_RES, sTENAGAS_RES)])\n", + "plt.bar(years, sTEBIOMA_RES, label='Biomass', color='brown', bottom=[sum(x) for x in zip(sTEELE_RES, sTEOPDIE_RES, sTENAGAS_RES, sTEOLPG_RES)])\n", + "plt.title('TE consumed by ST in RES sector')\n", + "plt.xlabel('Year')\n", + "plt.ylabel('[GWh]')\n", + "plt.legend()\n", + "plt.show()" ] }, { - "attachments": {}, - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_25612\\1076502512.py:50: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2025gasCE_TEELECE = d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2025')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2025')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2025')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2025')].vQCESecOUT.sum()\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_25612\\1076502512.py:51: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2030gasCE_TEELECE = d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2030')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2030')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2030')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2030')].vQCESecOUT.sum()\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_25612\\1076502512.py:52: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2035gasCE_TEELECE = d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2035')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2035')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2035')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2035')].vQCESecOUT.sum()\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_25612\\1076502512.py:53: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2040gasCE_TEELECE = d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2040')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2040')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2040')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2040')].vQCESecOUT.sum()\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_25612\\1076502512.py:54: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2045gasCE_TEELECE = d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2045')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2045')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2045')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2045')].vQCESecOUT.sum()\n", + "C:\\Users\\marios\\AppData\\Local\\Temp\\ipykernel_25612\\1076502512.py:55: UserWarning: Boolean Series key will be reindexed to match DataFrame index.\n", + " y2050gasCE_TEELECE = d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2050')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2050')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2050')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2050')].vQCESecOUT.sum()\n" + ] + }, + { + "data": { + "image/png": "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xeGYmBh88803OHnyJHr06IHvv/8eAQEBmDRpUpnzCIJgd4zjx4+/a5vvv/8egiBYh+tW9FolJBIJRowYgVWrViE3NxdeXl4AigtqPfDAA+UWXyqh0+kAoEyvtlartQ6bL3H8+HF07twZu3fvhkajwbPPPmvznkqlUnTr1g379u0rc51be1N79uxpUxzru+++g4+PD/r3729zzk6dOsHT0xP79u3Dc889Z90eHh6OmJiYMtcpPW9bq9XCaDQiOjoau3btglarhY+Pz23fi/L88ccfyMjIwLx582zmcg8aNAgtW7bE9u3brUXz7L1Xezz33HNYsGAB1q1bh//85z+QSqV44okncOLECbuOd3d3x6ZNm9CrVy/06tULx44dw6effopGjRo5FEeJPXv2wGAwYMqUKTZF+8aOHYvXX38d27dvx6hRo6zblUqlzWtnmjNnDnr27Flmu7+/v83rbt264Z133inT7nbV3u/1uiU/SyU/f/Zy9PcaERE5H5NtIrrvde3a1aFCQpmZmdBoNPjoo49uO4y3pBhUYmIiWrRoAZms4r9uZTKZXfMxExMTUb9+/TLJwb148cUXsXTpUvz444948cUXceHCBZw4cQIbNmy443EliUFeXp7Ndk9PT+zevRsA8Msvv+Ddd9+17ktISABQPFy5PN7e3javS+akl+bn52czFzshIQFarfa2w6RLvk8lbvcBwuHDhzF37lwcOXIEBQUFNvsqkmxfuXIFAMqd996yZUscOnTIZps992qP4cOHY/r06dixYwe+/PJLDB482OEkrkePHhg/fjzWrl2LmJgYjB492qHjS7vd+6BQKNC4cWPr/hIly8dVhjZt2qBfv353bRcQEGBXO2ddt+TffW5urkPndfT3GhEROR+TbSIiB5UUmHr++ecRGxtbbpu2bds67XpKpdKm168qRUZGolOnTvjiiy/w4osv4osvvoBCoSi3oFZpLVu2BACcPXvWZrtMJrMmFqmpqTb7St7XLVu2oF69emXOeesHFvb00lksFgQFBeHLL78sd/+tCWx5lccTExPRt29ftGzZEu+//z5CQkKgUCjwv//9DytWrKjQ8muOclaPZHBwMHr37o3ly5fj8OHDZSqQ26OoqMg67zsxMbHciuCVxRmV4Wuakp+lv/76y1pDgIiIagYm20REDgoMDISXlxfMZvNde7iaNGmC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AtU+TLarUMnQcW9vbybbRERERETE6aW1GCcHEBERERERETkZk20iIiIiIiIiJ2OyTURERERERORkTLaJiIiIiIiInIzJNhEREREREZGTMdkmIiIiIiIicjIm20REREREREROxmSbiIiIiIiIyMmYbBMRERERERE5GZNtIiIiIiIiIidjsk1ERERERETkZEy2iYiIiIiIiJyMyTYRERERERGRkzHZJiIiIiIiInIyJttERERERERETiZzdQBERERERET3ymwugsGQjqKiDBQZMmAoyrB9bsiAt3d7REYscXWodJ9gsk1ERERERNWW2axHUVE6DIZMFBWl2yTPRUUZ1u0mk+6u53J3b1wFERMVY7JNRERERERVzmwuvJk8Z8Jw82tRUToMRZkoMqSjqCgTBkM6TKZcV4dKVCFMtomIiIiIyGnM5oLiJPpm0mwo/bVUUm0257k6VKJKxWSbiIiIiIjuymTKh+Hm0G3bYd2ZpV5nMIkmuonJNhERERHRfcxkyrs59/mWgmK3JNJmc76rQyWqUZhsExERERHVQiZTbplq3EVFZYuLMYkmqhxMtomIiIiIahCjUXezF/rOxcUslkJXh0p0X2OyTURERERUDRiN2tuuD126R9pi0bs6VCKyA5NtIiIiIqJKZDRqbpkLXU4ibchkEk1UyzDZJiIiIiKqAKMx52ZlbtviYqVfFyfRRa4OlYhcgMk2EREREREAUTTDZMqF0aiFyaQt7pG+zVDu4iTa4OqQiagaY7JNRERERLWG2VxUnCibtDCZdDAZdaWea2E06W77vLgqt+jqWyCiWoLJNhERERFVG6IowmzOu9m7fDNRNupKPdcW9z6Xl0CbtOxtJqJqg8k2ERERETmVxWKEyaS1HZJ9s5f5n+elk2YtTMaS57kALK6+BSKie8Zkm4iIiIjKMJnyb/YW66y9zKWTZmvPss3+4udc35mIiMk2ERERUa10a7Evay+ydXh2+Yly8fNciKLR1bdARFSjMdkmIiIiqqZY7IuIqOZisk1ERERUSe5a7OtOCTSLfRER1WhMtomIiIjugcViwrVrX0KjOV6m2JfZnAdRNLs6RCIicgEm20REREQVpFYfxMWEd1BQcMnVoRARUTXDZJuIiIjIQQUFV5BwaRGysva4OhQiIqqmmGwTERER2clkykfylXW4evUzzqcmIqI7YrJNRERE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sADJycno27cvZLLiwy0WC1588UUsWrTI6QESVTfWImVuPvCTskgZERERERGV5XCyrVAosHXrVixYsABnzpyBm5sb2rRpg9DQUIcvvnjxYvzwww+Ij4+Hm5sbHnjgASxduhQtWrSwttHr9Xj11VfxzTffoKioCDExMVi3bh3q1q1rbZOSkoLx48dj37598PT0RGxsLBYvXmz9MAAA4uLiMG3aNPz9998ICQnBm2++iZEjR9rEs3btWrz77rtIS0tDu3btsHr1anTt2tWhWKj2kMvlqOPjD3+VN3ytRcoU8NBIIClgUk1EREREVWvevHm17npxcXHo06cPcnJy4OvrW+HzjBw5EhqNBtu2bXNabPdKUtEDmzdvjqeffhqDBw+uUKINFA8/nzBhAn7//Xfs3r0bRqMRAwYMQH5+vrXN1KlT8dNPP+G7777D/v37cf36dTz55JPW/WazGYMGDYLBYMBvv/2GzZs3Y9OmTZgzZ461TVJSEgYNGoQ+ffrg9OnTmDJlCl566SXs2rXL2mbr1q2YNm0a5s6di5MnT6Jdu3aIiYlBRkaG3bFQzaRSqdAgqD7ahLREz4ad8GhQDzyn7I0X83picGprPHCpESIT/NHgihu8sqWQWJhoExERERHdasOGDfDy8oLJZLJuy8vLg1wuR+/evW3axsXFQRAEBAcH48aNG/Dx8aniaCufXT3b06ZNw4IFC+Dh4YFp06bdse37779v98V37txp83rTpk0ICgrCiRMn0KtXL2i1Wnz66af46quv8NBDDwEoXuc7IiICv//+O7p3745ffvkF586dw549e1C3bl20b98eCxYswMyZMzFv3jwoFAps2LAB4eHhWL58OQAgIiIChw4dwooVKxATE2ONe+zYsRg1ahSA4n8o27dvx2effYZZs2bZFQtVbzZFykQP+BSq4KWRQaWRABpXR0dEREREVLP16dMHeXl5+OOPP6z50cGDB1GvXj0cPXoUer0eKpUKALBv3z40atTIZlRzbWNXz/apU6dgNBoBACdPnsSpU6fKfZw+ffqegtFqi8sy+/v7AwBOnDgBo9GIfv36Wdu0bNkSjRo1wpEjRwAAR44cQZs2bWyGcsfExECn0+Hvv/+2til9jpI2JecwGAw4ceKETRuJRIJ+/fpZ29gTy62Kioqg0+lsHlS5BEGAr7cPmtQPQ+dGbdC3QTc8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RFRrSBw9YPLkyVi1alWZ7WvWrMGUKVOcERMRERERERFRjeZwsv3999+jR48eZbY/8MAD+M9//uOUoIiI/r+9ew+TojrQP/6eqr7N/QozjAw3IdwRFSVEE0NEMWYTyfrsGtTEGCOr4kaXXAxuIprdTVZ9XDU+KokxmGST1eQhElcjLoJ30R9qUFAhihJFmQFmmPutu+v8/ujLTMOgDPR0z+X7eZ5+uurUqdOn51g471TVKQAAAGAw63PYrqurS5mJPKGwsFD79u1LS6cAAAAAABjM+hy2J06cqLVr1x5U/uijj2rChAlp6RQAAAAAAINZnydIW7Zsma688krt3btXn/vc5yRJ69ev1y233KLbbrst3f0DAAAAAEhav+HYjH7e6Z/bkdHPk6Trr79ea9as0ebNmzP+2enW5zPb3/jGN3TLLbfo3nvv1fz58zV//nz993//t+6++25deuml/dFHAAAAAMAgsHfvXl1++eUaM2aMgsGgKisrtXDhQj333HMZ68P1118vY8xHviTp61//eq/bzjrrrLT0o89ntiXp8ssv1+WXX669e/cqJydH+fn5aekMAAAAAGDwOvfcc9XV1aVf/epXmjBhgmpra7V+/XrV1dVlrA/f/va3ddlllyXXTzrpJC1ZsqTXk8NnnXWWVq1alVIWDAbT0o8+n9mWpEgkoscff1x//OMfZa2VJH344YdqaWlJS6cAAAAAAINLQ0ODnnnmGd14442aP3++xo4dq5NPPlnLly/Xl770JUnSe++9p3POOUf5+fkqLCzUP/7jP6q2tvaQbW7atElnnHGGysvLVVRUpNNOO02vvPJKSh1jjO6++2596UtfUl5enm655RZVVlYmX67rqqCgIKUsIXH2veerpKQkLT+PPoftv/3tb5o5c6bOOeccLV26VHv37pUk3XjjjfrOd76Tlk4BAAAAAAaX/Px85efna82aNers7Dxou+d5Ouecc1RfX6+nnnpK69at0zvvvKPzzjvvkG02Nzfroosu0rPPPqsXXnhBkyZN0tlnn63m5uaUetdff72+/OUva8uWLfrGN76R9u92JPoctq+66irNmTNH+/fvV05OTrL8y1/+stavX5/WzgEAAAAABgefz6f77rtPv/rVr1RcXKxTTjlF1157rV577TVJsYm1t2zZot/97nc68cQTNXfuXP3617/WU089pU2b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6u///u/1b//2b3r99dc1ffp0ffOb39TXvvY1tbe365prrlEkEtGGDRskSatXr5YxRrNmzVJLS4uuu+467dy5U5s3b5bjONq5c6fGjx+vcePG6ZZbbtHxxx+vUCikUaNGZfnbAgCAj0PYBgAgDfbs2aPp06ervr5eq1ev1tatW/XMM8/oscceS9bZtWuXqqurtX37dn3iE584qI19+/ZpxIgR2rJli2bMmJEM27fddpuuuuqqTH4dAABwlLiMHACANBg5cqT+6Z/+SVOnTtWiRYv06quv6oknnlB+fn7yNWXKFElKXir+1ltvafHixZowYYIKCws1btw4SdJ7772X0vacOXMy+l0AAMDR82W7AwAADBU+n08+X+x/rS0tLfriF7+oG2+88aB6icvAv/jFL2rs2LG65557VFVVJc/zNGPGDHV1daXUz8vL6//OAwCAtCJsAwDQD0444QStXr1a48aNSwbwnurq6rR9+3bdc889+vSnPy1JevbZZzPdTQAA0E+4jBwAgH6wdOlS1dfXa/Hixdq0aZN27Nihxx57TBdffLGi0ahKSkpUVlamn//853r77be1YcMGLVu2LNvdBgAAaULYBgCgH1RVVem5555TNBrVmWeeqZkzZ+rqq69WcXGxHMeR4zi6//779fLLL2vGjBn6l3/5F918883Z7jYAAEgTZiMHAAAAACDNOLMNAAAAAECaEbYBAAAAAEgzwjYAAAAAAGlG2AYAAAAAIM0I2wAAAAAApBlhGwAAAACANCNsAwAAAACQZoRtAAAAAADSjLANAAAAAECaEbYBAAAAAEgzwjYAAAAAAGn2/wHfNGWqd4n61gAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "y2020_Nuclear_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCENUCLEAR')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum()\n", + "y2025_Nuclear_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCENUCLEAR')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum()\n", + "y2030_Nuclear_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCENUCLEAR')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum()\n", + "y2035_Nuclear_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCENUCLEAR')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum()\n", + "y2040_Nuclear_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCENUCLEAR')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum()\n", + "y2045_Nuclear_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCENUCLEAR')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum()\n", + "y2050_Nuclear_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCENUCLEAR')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum()\n", + "\n", + "y2020_solarPV_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCESOPHVCEWT')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum()\n", + "y2025_solarPV_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCESOPHVCEWT')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum()\n", + "y2030_solarPV_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCESOPHVCEWT')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum()\n", + "y2035_solarPV_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCESOPHVCEWT')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum()\n", + "y2040_solarPV_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCESOPHVCEWT')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum()\n", + "y2045_solarPV_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCESOPHVCEWT')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum()\n", + "y2050_solarPV_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCESOPHVCEWT')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum()\n", + "\n", + "y2020solarTELC_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCESOTELCE')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum()\n", + "y2025solarTELC_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCESOTELCE')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum()\n", + "y2030solarTELC_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCESOTELCE')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum()\n", + "y2035solarTELC_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCESOTELCE')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum()\n", + "y2040solarTELC_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCESOTELCE')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum()\n", + "y2045solarTELC_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCESOTELCE')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum()\n", + "y2050solarTELC_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCESOTELCE')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum()\n", + "\n", + "y2020_wind_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEWINDON')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum()\n", + "y2025_wind_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEWINDON')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum()\n", + "y2030_wind_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEWINDON')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum()\n", + "y2035_wind_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEWINDON')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum()\n", + "y2040_wind_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEWINDON')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum()\n", + "y2045_wind_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEWINDON')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum()\n", + "y2050_wind_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEWINDON')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum()\n", + "\n", + "y2020hydro_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEHYRURIV')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEHYRSCAP')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEMINIHYDR')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum()+ d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEHYPSTOR')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2020')].vQCESecOUT.sum()\n", + "y2025hydro_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEHYRURIV')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEHYRSCAP')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEMINIHYDR')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum()+ d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEHYPSTOR')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2025')].vQCESecOUT.sum()\n", + "y2030hydro_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEHYRURIV')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEHYRSCAP')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEMINIHYDR')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum()+ d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEHYPSTOR')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2030')].vQCESecOUT.sum()\n", + "y2035hydro_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEHYRURIV')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEHYRSCAP')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEMINIHYDR')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum()+ d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEHYPSTOR')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2035')].vQCESecOUT.sum()\n", + "y2040hydro_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEHYRURIV')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEHYRSCAP')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEMINIHYDR')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum()+ d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEHYPSTOR')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2040')].vQCESecOUT.sum()\n", + "y2045hydro_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEHYRURIV')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEHYRSCAP')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEMINIHYDR')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum()+ d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEHYPSTOR')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2045')].vQCESecOUT.sum()\n", + "y2050hydro_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEHYRURIV')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEHYRSCAP')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEMINIHYDR')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum()+ d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEHYPSTOR')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2050')].vQCESecOUT.sum()\n", + "\n", + "y2020coalCE_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOTRA')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOIGCC')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCPC')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCCCS')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum()\n", + "y2025coalCE_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOTRA')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOIGCC')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCPC')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCCCS')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum()\n", + "y2030coalCE_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOTRA')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOIGCC')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCPC')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCCCS')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum()\n", + "y2035coalCE_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOTRA')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOIGCC')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCPC')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCCCS')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum()\n", + "y2040coalCE_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOTRA')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOIGCC')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCPC')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCCCS')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum()\n", + "y2045coalCE_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOTRA')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOIGCC')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCPC')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCCCS')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum()\n", + "y2050coalCE_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOTRA')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOIGCC')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCPC')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum() + d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEIMCOSCCCS')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum()\n", + "\n", + "y2020gasCE_TEELECE = d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2020')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2020')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2020')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2020')].vQCESecOUT.sum()\n", + "y2025gasCE_TEELECE = d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2025')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2025')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2025')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2025')].vQCESecOUT.sum()\n", + "y2030gasCE_TEELECE = d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2030')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2030')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2030')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2030')].vQCESecOUT.sum()\n", + "y2035gasCE_TEELECE = d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2035')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2035')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2035')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2035')].vQCESecOUT.sum()\n", + "y2040gasCE_TEELECE = d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2040')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2040')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2040')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2040')].vQCESecOUT.sum()\n", + "y2045gasCE_TEELECE = d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2045')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2045')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2045')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2045')].vQCESecOUT.sum()\n", + "y2050gasCE_TEELECE = d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2050')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCECCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2050')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTTRA')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCESecOUT'].sYear=='y2050')].vQCESecOUT.sum() + d_vars['vQCESecOUT'][(d_vars['vQCESecOUT'].sCE.str.startswith('sCEOCGTCCS')) & (d_vars['vQCESecOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2050')].vQCESecOUT.sum()\n", + "\n", + "\n", + "y2020bioeleCE_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEBIOELECE')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum()\n", + "y2025bioeleCE_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEBIOELECE')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum()\n", + "y2030bioeleCE_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEBIOELECE')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum()\n", + "y2035bioeleCE_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEBIOELECE')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum()\n", + "y2040bioeleCE_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEBIOELECE')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum()\n", + "y2045bioeleCE_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEBIOELECE')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum()\n", + "y2050bioeleCE_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCEBIOELECE')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum()\n", + "\n", + "y2020sldwast_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCESLDWAST')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2020')].vQCEPriOUT.sum()\n", + "y2025sldwast_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCESLDWAST')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2025')].vQCEPriOUT.sum()\n", + "y2030sldwast_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCESLDWAST')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2030')].vQCEPriOUT.sum()\n", + "y2035sldwast_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCESLDWAST')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2035')].vQCEPriOUT.sum()\n", + "y2040sldwast_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCESLDWAST')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2040')].vQCEPriOUT.sum()\n", + "y2045sldwast_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCESLDWAST')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2045')].vQCEPriOUT.sum()\n", + "y2050sldwast_TEELECE = d_vars['vQCEPriOUT'][(d_vars['vQCEPriOUT'].sCE.str.startswith('sCESLDWAST')) & (d_vars['vQCEPriOUT'].sTE.str.startswith('sTEELECE')) & (d_vars['vQCEPriOUT'].sYear=='y2050')].vQCEPriOUT.sum()\n", + "\n", + "# Graph\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "Nuclear_TEELECE = [y2020_Nuclear_TEELECE, y2025_Nuclear_TEELECE, y2030_Nuclear_TEELECE, y2035_Nuclear_TEELECE, y2040_Nuclear_TEELECE, y2045_Nuclear_TEELECE, y2050_Nuclear_TEELECE]\n", + "Hydro_TEELECE = [y2020hydro_TEELECE, y2025hydro_TEELECE, y2030hydro_TEELECE, y2035hydro_TEELECE, y2040hydro_TEELECE, y2045hydro_TEELECE, y2050hydro_TEELECE]\n", + "Coal_TEELECE = [y2020coalCE_TEELECE, y2025coalCE_TEELECE, y2030coalCE_TEELECE, y2035coalCE_TEELECE, y2040coalCE_TEELECE, y2045coalCE_TEELECE, y2050coalCE_TEELECE]\n", + "Gas_TEELECE = [y2020gasCE_TEELECE, y2025gasCE_TEELECE, y2030gasCE_TEELECE, y2035gasCE_TEELECE, y2040gasCE_TEELECE, y2045gasCE_TEELECE, y2050gasCE_TEELECE]\n", + "Bioele_TEELECE = [y2020bioeleCE_TEELECE, y2025bioeleCE_TEELECE, y2030bioeleCE_TEELECE, y2035bioeleCE_TEELECE, y2040bioeleCE_TEELECE, y2045bioeleCE_TEELECE, y2050bioeleCE_TEELECE]\n", + "Sldwast_TEELECE = [y2020sldwast_TEELECE, y2025sldwast_TEELECE, y2030sldwast_TEELECE, y2035sldwast_TEELECE, y2040sldwast_TEELECE, y2045sldwast_TEELECE, y2050sldwast_TEELECE]\n", + "SolarPV_TEELECE = [y2020_solarPV_TEELECE, y2025_solarPV_TEELECE, y2030_solarPV_TEELECE, y2035_solarPV_TEELECE, y2040_solarPV_TEELECE, y2045_solarPV_TEELECE, y2050_solarPV_TEELECE]\n", + "Wind_TEELECE = [y2020_wind_TEELECE, y2025_wind_TEELECE, y2030_wind_TEELECE, y2035_wind_TEELECE, y2040_wind_TEELECE, y2045_wind_TEELECE, y2050_wind_TEELECE]\n", + "SolarTE_TEELECE = [y2020solarTELC_TEELECE, y2025solarTELC_TEELECE, y2030solarTELC_TEELECE, y2035solarTELC_TEELECE, y2040solarTELC_TEELECE, y2045solarTELC_TEELECE, y2050solarTELC_TEELECE]\n", + "\n", + "# Make an area chart with the data considering each as a portion of the whole\n", + "plt.figure(figsize=(10, 5))\n", + "plt.stackplot(years, Nuclear_TEELECE, Hydro_TEELECE, Coal_TEELECE, Gas_TEELECE, Bioele_TEELECE, Sldwast_TEELECE, SolarPV_TEELECE, Wind_TEELECE, SolarTE_TEELECE, labels=['Nuclear', 'Hydro', 'Coal', 'Gas', 'Bioele', 'Sldwast', 'SolarPV', 'Wind', 'SolarTE'])\n", + "plt.legend(loc='upper left')\n", + "# put the leged out of the plot\n", + "plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))\n", + "plt.title('Electricity Generation Mix for TEELECE')\n", + "plt.xlabel('Year')\n", + "plt.ylabel('Electricity Generation (GWh)')\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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ism9e/cgl8uhpaUFVVVVqKqqFlvn1TbeFst/aWhoQENDoxQ9QURERERVQbmOhAuCAH9/f+zatQuHDx+GtbW1Qnnz5s1RrVo1REZGiscSEhKQnJwMZ2dnAICzszMuX76ssIpJREQE5HI5GjRoINZ5tY3COoVtqKuro3nz5gp18vPzERkZKdYpSSxERERERCVRriPhfn5+2Lx5M/bs2QM9PT1xbrW+vj60tLSgr6+PIUOGICAgAIaGhpDL5Rg1ahScnZ3F1Ui6dOmCBg0aYMCAAZg3bx5SU1Mxbdo0+Pn5iaPQI0aMwIoVKzBx4kR8+eWXOHz4MH799Vfs379fjCUgIACDBg1CixYt0KpVKyxZsgRPnz7F4MGDxZjeFgsRERERUUmUaxK+cuVKAEDHjh0VjoeGhsLX1xcAsHjxYqioqKB3797Izs6Gu7s7QkJCxLqqqqrYt28fvv76azg7O0NHRweDBg3CjBkzxDrW1tbYv38/xo0bh6VLl6J27dpYu3Yt3N3dxTp9+/bF/fv3MX36dKSmpqJZs2YIDw9X+LLm22IhIiIiIiqJCrVOeGXHdcJL513XCWdfEBGRMnGdcCoLFWZ1FCIiIiKiqoJJOBERERGRxJiEExERERFJjEk4EREREZHEmIQTEREREUmMSTgRERERkcSYhBMRERERSYxJOBERERGRxJiEExERERFJjEk4EREREZHEmIQTEREREUlMrbwDIOUIDAwq7xDKQGB5B0BERERUJjgSTkREREQkMSbhREREREQSYxJORERERCQxJuFERERERBJjEk5EREREJDEm4UREREREEmMSTkREREQkMSbhREREREQSYxJORERERCQxJuFERERERBJjEk5EREREJDEm4UREREREEmMSTkREREQkMSbhREREREQSYxJORERERCQxJuFERERERBJjEk5EREREJDEm4UREREREEmMSTkREREQkMbXyDoCIiIjoQycIAl6+fIm8vLzyDoXKiaqqKtTU1CCTyUpUn0k4ERER0XvIyclBSkoKnj17Vt6hUDnT1taGmZkZ1NXV31qXSTgRERHRO8rPz0diYiJUVVVhbm4OdXX1Eo+EUuUhCAJycnJw//59JCYmws7ODioqb571zSS8kgiWBZV3CEoXKJR3BERERG+Wk5OD/Px8WFhYQFtbu7zDoXKkpaWFatWq4fbt28jJ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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ - "Loading variable information from .csv to a dictionary containing all outputs" + "y2020_sTEELE_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEELE')) & (d_vars['vQSTInTE'].sYear=='y2020') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2025_sTEELE_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEELE')) & (d_vars['vQSTInTE'].sYear=='y2025') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2030_sTEELE_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEELE')) & (d_vars['vQSTInTE'].sYear=='y2030') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2035_sTEELE_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEELE')) & (d_vars['vQSTInTE'].sYear=='y2035') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2040_sTEELE_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEELE')) & (d_vars['vQSTInTE'].sYear=='y2040') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2045_sTEELE_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEELE')) & (d_vars['vQSTInTE'].sYear=='y2045') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2050_sTEELE_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEELE')) & (d_vars['vQSTInTE'].sYear=='y2050') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEOPDIE_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (d_vars['vQSTInTE'].sYear=='y2020') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2025_sTEOPDIE_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (d_vars['vQSTInTE'].sYear=='y2025') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2030_sTEOPDIE_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (d_vars['vQSTInTE'].sYear=='y2030') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2035_sTEOPDIE_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (d_vars['vQSTInTE'].sYear=='y2035') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2040_sTEOPDIE_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (d_vars['vQSTInTE'].sYear=='y2040') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2045_sTEOPDIE_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (d_vars['vQSTInTE'].sYear=='y2045') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2050_sTEOPDIE_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPDIE')) & (d_vars['vQSTInTE'].sYear=='y2050') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEOLPG_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPLPG')) & (d_vars['vQSTInTE'].sYear=='y2020') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2025_sTEOLPG_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPLPG')) & (d_vars['vQSTInTE'].sYear=='y2025') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2030_sTEOLPG_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPLPG')) & (d_vars['vQSTInTE'].sYear=='y2030') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2035_sTEOLPG_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPLPG')) & (d_vars['vQSTInTE'].sYear=='y2035') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2040_sTEOLPG_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPLPG')) & (d_vars['vQSTInTE'].sYear=='y2040') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2045_sTEOLPG_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPLPG')) & (d_vars['vQSTInTE'].sYear=='y2045') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2050_sTEOLPG_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPLPG')) & (d_vars['vQSTInTE'].sYear=='y2050') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEBIOETH_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEBIOETH')) & (d_vars['vQSTInTE'].sYear=='y2020') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2025_sTEBIOETH_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEBIOETH')) & (d_vars['vQSTInTE'].sYear=='y2025') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2030_sTEBIOETH_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEBIOETH')) & (d_vars['vQSTInTE'].sYear=='y2030') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2035_sTEBIOETH_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEBIOETH')) & (d_vars['vQSTInTE'].sYear=='y2035') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2040_sTEBIOETH_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEBIOETH')) & (d_vars['vQSTInTE'].sYear=='y2040') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2045_sTEBIOETH_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEBIOETH')) & (d_vars['vQSTInTE'].sYear=='y2045') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2050_sTEBIOETH_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEBIOETH')) & (d_vars['vQSTInTE'].sYear=='y2050') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEBIODIE_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEBIODIE')) & (d_vars['vQSTInTE'].sYear=='y2020') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2025_sTEBIODIE_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEBIODIE')) & (d_vars['vQSTInTE'].sYear=='y2025') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2030_sTEBIODIE_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEBIODIE')) & (d_vars['vQSTInTE'].sYear=='y2030') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2035_sTEBIODIE_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEBIODIE')) & (d_vars['vQSTInTE'].sYear=='y2035') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2040_sTEBIODIE_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEBIODIE')) & (d_vars['vQSTInTE'].sYear=='y2040') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2045_sTEBIODIE_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEBIODIE')) & (d_vars['vQSTInTE'].sYear=='y2045') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2050_sTEBIODIE_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEBIODIE')) & (d_vars['vQSTInTE'].sYear=='y2050') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEOPGSN_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPGSN')) & (d_vars['vQSTInTE'].sYear=='y2020') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2025_sTEOPGSN_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPGSN')) & (d_vars['vQSTInTE'].sYear=='y2025') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2030_sTEOPGSN_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPGSN')) & (d_vars['vQSTInTE'].sYear=='y2030') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2035_sTEOPGSN_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPGSN')) & (d_vars['vQSTInTE'].sYear=='y2035') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2040_sTEOPGSN_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPGSN')) & (d_vars['vQSTInTE'].sYear=='y2040') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2045_sTEOPGSN_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPGSN')) & (d_vars['vQSTInTE'].sYear=='y2045') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2050_sTEOPGSN_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPGSN')) & (d_vars['vQSTInTE'].sYear=='y2050') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEOPKER_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPKER')) & (d_vars['vQSTInTE'].sYear=='y2020') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2025_sTEOPKER_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPKER')) & (d_vars['vQSTInTE'].sYear=='y2025') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2030_sTEOPKER_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPKER')) & (d_vars['vQSTInTE'].sYear=='y2030') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2035_sTEOPKER_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPKER')) & (d_vars['vQSTInTE'].sYear=='y2035') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2040_sTEOPKER_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPKER')) & (d_vars['vQSTInTE'].sYear=='y2040') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2045_sTEOPKER_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPKER')) & (d_vars['vQSTInTE'].sYear=='y2045') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2050_sTEOPKER_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPKER')) & (d_vars['vQSTInTE'].sYear=='y2050') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTEOPFOI_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPFOI')) & (d_vars['vQSTInTE'].sYear=='y2020') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2025_sTEOPFOI_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPFOI')) & (d_vars['vQSTInTE'].sYear=='y2025') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2030_sTEOPFOI_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPFOI')) & (d_vars['vQSTInTE'].sYear=='y2030') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2035_sTEOPFOI_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPFOI')) & (d_vars['vQSTInTE'].sYear=='y2035') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2040_sTEOPFOI_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPFOI')) & (d_vars['vQSTInTE'].sYear=='y2040') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2045_sTEOPFOI_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPFOI')) & (d_vars['vQSTInTE'].sYear=='y2045') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2050_sTEOPFOI_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTEOPFOI')) & (d_vars['vQSTInTE'].sYear=='y2050') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "\n", + "y2020_sTENAGAS_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (d_vars['vQSTInTE'].sYear=='y2020') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2025_sTENAGAS_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (d_vars['vQSTInTE'].sYear=='y2025') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2030_sTENAGAS_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (d_vars['vQSTInTE'].sYear=='y2030') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2035_sTENAGAS_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (d_vars['vQSTInTE'].sYear=='y2035') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2040_sTENAGAS_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (d_vars['vQSTInTE'].sYear=='y2040') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2045_sTENAGAS_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (d_vars['vQSTInTE'].sYear=='y2045') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "y2050_sTENAGAS_TRA = d_vars['vQSTInTE'][(d_vars['vQSTInTE'].sTE.str.startswith('sTENAGAS')) & (d_vars['vQSTInTE'].sYear=='y2050') & (d_vars['vQSTInTE'].sST.str.startswith('sST_DSTRA'))].vQSTInTE.sum()\n", + "\n", + "# Graph bar stackplot\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "sTEELE_TRA = [y2020_sTEELE_TRA, y2025_sTEELE_TRA, y2030_sTEELE_TRA, y2035_sTEELE_TRA, y2040_sTEELE_TRA, y2045_sTEELE_TRA, y2050_sTEELE_TRA]\n", + "sTEOPDIE_TRA = [y2020_sTEOPDIE_TRA, y2025_sTEOPDIE_TRA, y2030_sTEOPDIE_TRA, y2035_sTEOPDIE_TRA, y2040_sTEOPDIE_TRA, y2045_sTEOPDIE_TRA, y2050_sTEOPDIE_TRA]\n", + "sTEOLPG_TRA = [y2020_sTEOLPG_TRA, y2025_sTEOLPG_TRA, y2030_sTEOLPG_TRA, y2035_sTEOLPG_TRA, y2040_sTEOLPG_TRA, y2045_sTEOLPG_TRA, y2050_sTEOLPG_TRA]\n", + "sTEBIOETH_TRA = [y2020_sTEBIOETH_TRA, y2025_sTEBIOETH_TRA, y2030_sTEBIOETH_TRA, y2035_sTEBIOETH_TRA, y2040_sTEBIOETH_TRA, y2045_sTEBIOETH_TRA, y2050_sTEBIOETH_TRA]\n", + "sTEBIODIE_TRA = [y2020_sTEBIODIE_TRA, y2025_sTEBIODIE_TRA, y2030_sTEBIODIE_TRA, y2035_sTEBIODIE_TRA, y2040_sTEBIODIE_TRA, y2045_sTEBIODIE_TRA, y2050_sTEBIODIE_TRA]\n", + "sTEOPGSN_TRA = [y2020_sTEOPGSN_TRA, y2025_sTEOPGSN_TRA, y2030_sTEOPGSN_TRA, y2035_sTEOPGSN_TRA, y2040_sTEOPGSN_TRA, y2045_sTEOPGSN_TRA, y2050_sTEOPGSN_TRA]\n", + "sTEOPKER_TRA = [y2020_sTEOPKER_TRA, y2025_sTEOPKER_TRA, y2030_sTEOPKER_TRA, y2035_sTEOPKER_TRA, y2040_sTEOPKER_TRA, y2045_sTEOPKER_TRA, y2050_sTEOPKER_TRA]\n", + "sTEOPFOI_TRA = [y2020_sTEOPFOI_TRA, y2025_sTEOPFOI_TRA, y2030_sTEOPFOI_TRA, y2035_sTEOPFOI_TRA, y2040_sTEOPFOI_TRA, y2045_sTEOPFOI_TRA, y2050_sTEOPFOI_TRA]\n", + "sTENAGAS_TRA = [y2020_sTENAGAS_TRA, y2025_sTENAGAS_TRA, y2030_sTENAGAS_TRA, y2035_sTENAGAS_TRA, y2040_sTENAGAS_TRA, y2045_sTENAGAS_TRA, y2050_sTENAGAS_TRA]\n", + "\n", + "plt.bar(years, sTEELE_TRA, label='Electricity', color='blue')\n", + "plt.bar(years, sTEOPDIE_TRA, label='Diesel', color='red', bottom=sTEELE_TRA)\n", + "plt.bar(years, sTEOLPG_TRA, label='LPG', color='green', bottom=[sum(x) for x in zip(sTEELE_TRA, sTEOPDIE_TRA)])\n", + "plt.bar(years, sTEBIOETH_TRA, label='Bioethanol', color='orange', bottom=[sum(x) for x in zip(sTEELE_TRA, sTEOPDIE_TRA, sTEOLPG_TRA)])\n", + "plt.bar(years, sTEBIODIE_TRA, label='Biodiesel', color='brown', bottom=[sum(x) for x in zip(sTEELE_TRA, sTEOPDIE_TRA, sTEOLPG_TRA, sTEBIOETH_TRA)])\n", + "plt.bar(years, sTEOPGSN_TRA, label='Gasoline', color='purple', bottom=[sum(x) for x in zip(sTEELE_TRA, sTEOPDIE_TRA, sTEOLPG_TRA, sTEBIOETH_TRA, sTEBIODIE_TRA)])\n", + "plt.bar(years, sTEOPKER_TRA, label='Kerosene', color='yellow', bottom=[sum(x) for x in zip(sTEELE_TRA, sTEOPDIE_TRA, sTEOLPG_TRA, sTEBIOETH_TRA, sTEBIODIE_TRA, sTEOPGSN_TRA)])\n", + "plt.bar(years, sTEOPFOI_TRA, label='Fuel Oil', color='pink', bottom=[sum(x) for x in zip(sTEELE_TRA, sTEOPDIE_TRA, sTEOLPG_TRA, sTEBIOETH_TRA, sTEBIODIE_TRA, sTEOPGSN_TRA, sTEOPKER_TRA)])\n", + "plt.bar(years, sTENAGAS_TRA, label='Natural Gas', color='grey', bottom=[sum(x) for x in zip(sTEELE_TRA, sTEOPDIE_TRA, sTEOLPG_TRA, sTEBIOETH_TRA, sTEBIODIE_TRA, sTEOPGSN_TRA, sTEOPKER_TRA, sTEOPFOI_TRA)])\n", + "plt.title('TE consumed by ST in TRA sector')\n", + "plt.xlabel('Year')\n", + "plt.ylabel('[GWh]')\n", + "plt.legend()\n", + "plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))\n", + "plt.show()" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 14, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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KjQ0NMezKLp27ar+/fvbXn/55Zdq3LixvLy8VKNGDY0ePdou11ksFs2YMUMPP/ywvL29VatWLS1dulTS1ZDfpk0bSVKFChVksVjUr18/SVenVQwbNszWz6lTp9SnTx9VqFBB3t7e6tSpk/bv3287Pnv2bPn7+2vVqlWqW7eufHx89MADDyg1NdXWZvv27Wrfvr0CAgLk5+enVq1a6ccff7yV/yluyOFwfP78eT311FPy9vZW/fr1dfDgQUnSP/7xD40fP97pBQIAALiDkydPauXKlYqOjla5cuVyHPf391d2dra6du2qkydPKiEhQatXr9bvv/+unj172rVNTk7WkiVLtHz5ci1fvlwJCQm2HPbII4/oxIkTWr9+fY7PfvzxxyVJmzZtUp8+ffTcc89p7969mjZtmmbPnq2xY8fafc7o0aP16KOPateuXercubMef/xxnTx5UmFhYVq4cKEkKTExUampqZo0aVKu592vXz/98MMPWrp0qbZs2SLDMNS5c2e7x36fP39e/+///T/NnTtXGzdu1MGDB/XCCy/Yjp85c0Z9+/bV5s2btXXrVtWqVUudO3e2/R8CZ3I4HMfGxurnn3/Whg0b5OXlZdvfrl07LViwwKnFAQAAuIukpCQZhqE6dercsM3atWu1e/duzZ8/X02aNFGzZs300UcfKSEhQdu3b7e1y87O1uzZsxUREaH77rtPTzzxhNauXSvp6p3cTp06af78+bb2X3zxhQICAmx3e0ePHq2XX35Zffv2VY0aNdS+fXu9/vrrmjZtml09/fr1U69evVSzZk29+eabOnv2rL7//nuVKlXKNn0iMDBQwcHB8vPzy3E++/fv19KlSzVjxgzdd999atiwoebNm6f//ve/WrJkia3d5cuXNXXqVDVt2lSNGzfWkCFDbOcjSffff7969+6tOnXqqG7duvrwww91/vz5HN9/cwaHw/GSJUv0/vvvq0WLFnZrxtWvX1/JyclOLQ4AAMBdGHn4Bt+vv/6qsLAwhYWF2fbVq1dP/v7++vXXX237qlWrpvLly9teh4SE6NixY7bXjz/+uBYuXKjMzExJ0rx58/TYY4/Jw+Nq9Pv55581ZswY+fj42LYBAwYoNTVV58+ft/UTGRlp+7lcuXLy9fW1+5y8nE/p0qXVrFkz275KlSqpdu3adufj7e2t22+//Ybnc/ToUQ0YMEC1atWSn5+ffH19dfbsWdsMBmdy+Al5//vf/xQYGJhj/7lz51iMGwAA4AZq1aoli8XilC/d/Xk1CIvFYjfHuEuXLjIMQytWrNBdd92lTZs22a0+dvbsWY0ePVrdu3fP0ff1MwP+6nOcJbfPuf7/TPTt21cnTpzQpEmTFB4eLqvVqqioKF26dMnptTh857hp06ZasWKF7fW1QDxjxgxFRUU5rzIAAAA3UrFiRXXs2FFTpkzRuXPnchw/ffq06tatq0OHDunQoUO2/Xv37tXp06dVr169PH+Wl5eXunfvrnnz5umTTz5R7dq11bhxY9vxxo0bKzExUTVr1syxXbu7/FeufyTzjdStW1dXrlzRtm3bbPtOnDihxMREh87n22+/1dChQ9W5c2fVr19fVqtVx48fz/P7HeHwneM333xTnTp10t69e3XlyhVNmjRJe/fu1XfffVcg8z4AAADcxZQpU9S8eXPdfffdGjNmjCIjI3XlyhWtXr1acXFx2rt3rxo0aKDHH39cEydO1JUrVzR48GC1atVKTZs2deizHn/8cT344IP65Zdf1Lt3b7tjr732mh588EFVrVpVf/vb3+Th4aGff/5Ze/bs0RtvvJGn/sPDw2WxWLR8+XJ17txZZcuWlY+Pj12bWrVqqWvXrhowYICmTZum8uXL6+WXX9Ztt92mrl275vlcatWqpblz56pp06bKyMjQiy++qLJly+b5/Y5w+M5xixYttHPnTl25ckUNGjTQN998o8DAQG3ZskVNmjQpiBoBAADcQo0aNfTjjz+qTZs2ev755xUREaH27dtr7dq1iouLk8Vi0ZdffqkKFSqoZcuWateunWrUqJGvRQ/uv/9+VaxYUYmJifr73/9ud6xjx45avny5vvnmG91111265557NGHCBIWHh+e5/9tuu832xb6goCANGTIk13bx8fFq0qSJHnzwQUVFRckwDH311VcOPShk5syZOnXqlBo3bqwnnnhCQ4cOzXWarzNYjLzMDi/GMjIy5Ofnp/T0dPn6+jq1b3ecYp3fq4GxuIpxuMoy2v0GwhiZv18OxuIqxuEqxiHvbvb3++LFi0pJSVH16tXt5scCN+LINePwneN27dpp9uzZysjIyHeBAAAAQFHkcDiuX7++YmNjFRwcrEceeURffvml3SLOjhg3bpzuuusulS9fXoGBgerWrZsSExPt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7dy5U6VKlVKrVq0c7ru4czgcS9Lf/va3HPv69u17y8UAAAC4u3LlytmmPtzM2bNn1aRJE82bNy/HscqVK8vDI/8r8pYrV+6mx8uWLZvvvou7fIXjtWvXau3atTp27Jiys7Ptjs2aNcsphQEAAJRkjRs31oIFCxQYGChfX99c21SrVk1r165VmzZtcj1epkwZZWVlOfzZDRo0UHZ2thISEmzTKkoKh/8vx+jRo9WhQwetXbtWx48f16lTp+w2AAAA3FhmZqbS0tLstuPHj+do9/jjjysgIEBdu3bVpk2blJKSog0bNmjo0KE6fPiwpKvTXd955x1NnjxZ+/fv148//qj33nvP1se18JyWluZQTqtWrZr69u2r/v37a8mSJbbP/uyzz259AIo4h+8cT506VbNnz9YTTzxREPUAAAC4tZUrVyokJMRuX+3atbVv3z67fd7e3tq4caNeeuklde/eXWfOnNFtt92mtm3b2u4k9+3bVxcvXtSECRP0wgsvKCAgwG766zvvvKOYmBhNnz5dt912W45l4G4mLi5Or7zyigYPHqwTJ06oatWqOb406I4shmE49HiXSpUq6fvvv9ftt99eUDU5VUZGhvz8/JSenn7Df5LIL0vhPoinUDh2NfyBsbiKcTAxEDaF/cSuwpCfp4IxDlcxDnl3s7/fFy9eVEpKit0avcDNOHLNODyt4umnn9b8+fPzXRwAAABQVDk8reLixYv68MMPtWbNGkVGRuZ4Bve7777rtOIAAACAwuRwON61a5caNWokSdqzZ4/dMYs7/lMqAAAASgyHw/H69esLog4AAADA5fK/erSkw4cP25YSAQAAAIo7h8Nxdna2xowZIz8/P4WHhys8PFz+/v56/fXXczwQBAAAoKCQO5BXjizO5vC0in/+85+aOXOmxo8fr+bNm0uSNm/erFGjRunixYsaO3aso10CAADkmaenpzw8PHTkyBFVrlxZnp6efO8JN2QYhv73v//JYrHkWEgiNw6H4zlz5mjGjBl66KGHbPsiIyN12223afDgwYRjAABQoDw8PFS9enWlpqbqyJEjri4HxYDFYlGVKlVUqlSpv2zrcDg+efKk6tSpk2N/nTp1dPLkSYf62rhxo95++23t2LFDqampWrx4sbp162Y73q9fP82ZM8fuPR07dtTKlSsdLRsAALgRT09PVa1aVVeuXFFW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9epla1PUr4nCGoeifj0YhnPG4npdu3Y1OnXqZEgyTp06ZdtfEq6J691oHIr6NeGscZBkxMfH253jhQsXbMeL+vUAuALh2AWOHTtmSDISEhIMwzCM06dPG2XKlDE+//xzW5tff/3VkGRs2bLlhv0MHjzYaNOmje31iBEjjPr169u16dmzp9GxY0cnn4HzFNRYXPvDd/0fw6LMWeMwadIko0qVKrbXxe2aKKhxKG7Xg2Hc2lh88MEHRqtWrYy1a9fmOO+SdE3cbByK2zWR33GQZCxevPiG/Ra36wEoDEyrcIH09HRJUsWKFSVJO3bs0OXLl9WuXTtbmzp16qhq1arasmXLTfu51ockbdmyxa4PSerYseNN+3C1ghqLaxo1aqSQkBC1b99e3377rZOrdx5njMORI0e0aNEitWrVyravuF0TBTUO1xSX60HK/1js3btXY8aM0UcffSQPj5z/iS8p18RfjcM1xeWauJXfjejoaAUEBOjuu+/WrFmzZFz3eIPidj0AhYFwXMiys7M1bNgwNW/eXBEREZKktLQ0eXp6yt/f365tUFDQDee/fffdd1qwYIEGDhxo25eWlpbjsdpBQUHKyMjQhQsXnHsiTlCQYxESEqKpU6dq4cKFWrhwocLCwtS6dWv9+OOPBXY++XWr49CrVy95e3vrtttuk6+vr2bMmGE7VpyuiYIch+J0PUj5H4vMzEz16tVLb7/9tqpWrZpr3yXhmsjLOBSna+JWfjfGjBmjzz77TKtXr1aPHj00ePBgvffee7bjxel6AApLsXh8tDuJjo7Wnj17tHnz5nz3sWfPHnXt2lUjR45Uhw4dnFhd4SrIsahdu7Zq165te33vvfcqOTlZEyZM0Ny5c2+pbme71XGYMGGCRo4cqd9++02xsbGKiYnRBx984OQqC15BjkNxuh6k/I9FbGys6tatq969exdQZYWrIMehOF0Tt/K78a9//cv285133qlz587p7bff1tChQ51ZIuBWuHNciIYMGaLly5dr/fr1qlKlim1/cHCwLl26lOMb5UePHlVwcLDdvr1796pt27YaOHCgXn31VbtjwcHBOb6pfPToUfn6+qps2bLOPZlbVNBjkZu7775bSUlJTqnfWZwxDsHBwapTp44eeughTZs2TXFxcUpNTbUdKw7XREGPQ26K4vUg3dpYrFu3Tp9//rlKly6t0qVL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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ - "d_vars = openMASTER.import_results_from_csv(output_path)" + "CarGasoline_2020 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2020') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSN'))].vSTTotCap.sum()\n", + "CarDiesel_2020 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2020') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADST'))].vSTTotCap.sum()\n", + "CarCNG_2020 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2020') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CACNG'))].vSTTotCap.sum()\n", + "CarLPG_2020 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2020') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CALPG'))].vSTTotCap.sum()\n", + "CarGasolineHyb_2020 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2020') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSNPIHYB'))].vSTTotCap.sum()\n", + "CarDieselHyb_2020 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2020') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADIEPIHYB'))].vSTTotCap.sum()\n", + "CarElectric_2020 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2020') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CABEV'))].vSTTotCap.sum()\n", + "\n", + "CarGasoline_2025 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2025') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSN'))].vSTTotCap.sum()\n", + "CarDiesel_2025 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2025') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADST'))].vSTTotCap.sum()\n", + "CarCNG_2025 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2025') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CACNG'))].vSTTotCap.sum()\n", + "CarLPG_2025 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2025') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CALPG'))].vSTTotCap.sum()\n", + "CarGasolineHyb_2025 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2025') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSNPIHYB'))].vSTTotCap.sum()\n", + "CarDieselHyb_2025 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2025') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADIEPIHYB'))].vSTTotCap.sum()\n", + "CarElectric_2025 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2025') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CABEV'))].vSTTotCap.sum()\n", + "\n", + "CarGasoline_2030 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2030') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSN'))].vSTTotCap.sum()\n", + "CarDiesel_2030 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2030') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADST'))].vSTTotCap.sum()\n", + "CarCNG_2030 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2030') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CACNG'))].vSTTotCap.sum()\n", + "CarLPG_2030 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2030') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CALPG'))].vSTTotCap.sum()\n", + "CarGasolineHyb_2030 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2030') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSNPIHYB'))].vSTTotCap.sum()\n", + "CarDieselHyb_2030 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2030') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADIEPIHYB'))].vSTTotCap.sum()\n", + "CarElectric_2030 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2030') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CABEV'))].vSTTotCap.sum()\n", + "\n", + "CarGasoline_2035 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2035') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSN'))].vSTTotCap.sum()\n", + "CarDiesel_2035 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2035') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADST'))].vSTTotCap.sum()\n", + "CarCNG_2035 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2035') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CACNG'))].vSTTotCap.sum()\n", + "CarLPG_2035 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2035') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CALPG'))].vSTTotCap.sum()\n", + "CarGasolineHyb_2035 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2035') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSNPIHYB'))].vSTTotCap.sum()\n", + "CarDieselHyb_2035 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2035') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADIEPIHYB'))].vSTTotCap.sum()\n", + "CarElectric_2035 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2035') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CABEV'))].vSTTotCap.sum()\n", + "\n", + "CarGasoline_2040 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2040') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSN'))].vSTTotCap.sum()\n", + "CarDiesel_2040 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2040') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADST'))].vSTTotCap.sum()\n", + "CarCNG_2040 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2040') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CACNG'))].vSTTotCap.sum()\n", + "CarLPG_2040 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2040') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CALPG'))].vSTTotCap.sum()\n", + "CarGasolineHyb_2040 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2040') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSNPIHYB'))].vSTTotCap.sum()\n", + "CarDieselHyb_2040 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2040') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADIEPIHYB'))].vSTTotCap.sum()\n", + "CarElectric_2040 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2040') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CABEV'))].vSTTotCap.sum()\n", + "\n", + "CarGasoline_2045 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2045') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSN'))].vSTTotCap.sum()\n", + "CarDiesel_2045 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2045') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADST'))].vSTTotCap.sum()\n", + "CarCNG_2045 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2045') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CACNG'))].vSTTotCap.sum()\n", + "CarLPG_2045 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2045') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CALPG'))].vSTTotCap.sum()\n", + "CarGasolineHyb_2045 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2045') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSNPIHYB'))].vSTTotCap.sum()\n", + "CarDieselHyb_2045 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2045') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADIEPIHYB'))].vSTTotCap.sum()\n", + "CarElectric_2045 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2045') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CABEV'))].vSTTotCap.sum()\n", + "\n", + "CarGasoline_2050 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2050') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSN'))].vSTTotCap.sum()\n", + "CarDiesel_2050 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2050') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADST'))].vSTTotCap.sum()\n", + "CarCNG_2050 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2050') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CACNG'))].vSTTotCap.sum()\n", + "CarLPG_2050 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2050') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CALPG'))].vSTTotCap.sum()\n", + "CarGasolineHyb_2050 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2050') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CAGSNPIHYB'))].vSTTotCap.sum()\n", + "CarDieselHyb_2050 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2050') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CADIEPIHYB'))].vSTTotCap.sum()\n", + "CarElectric_2050 = d_vars['vSTTotCap'][(d_vars['vSTTotCap'].sYear=='y2050') & (d_vars['vSTTotCap'].sST.str.startswith('sST_DSTRA_LNP_CABEV'))].vSTTotCap.sum()\n", + "\n", + "# Graph bar stackplot\n", + "years = ['2020', '2025', '2030', '2035', '2040', '2045', '2050']\n", + "Car_Conventional = [CarGasoline_2020 + CarDiesel_2020 + CarCNG_2020 + CarLPG_2020, CarGasoline_2025 + CarDiesel_2025 + CarCNG_2025 + CarLPG_2025, CarGasoline_2030 + CarDiesel_2030 + CarCNG_2030 + CarLPG_2030, CarGasoline_2035 + CarDiesel_2035 + CarCNG_2035 + CarLPG_2035, CarGasoline_2040 + CarDiesel_2040 + CarCNG_2040 + CarLPG_2040, CarGasoline_2045 + CarDiesel_2045 + CarCNG_2045 + CarLPG_2045, CarGasoline_2050 + CarDiesel_2050 + CarCNG_2050 + CarLPG_2050]\n", + "Car_Hybrid = [CarGasolineHyb_2020 + CarDieselHyb_2020, CarGasolineHyb_2025 + CarDieselHyb_2025, CarGasolineHyb_2030 + CarDieselHyb_2030, CarGasolineHyb_2035 + CarDieselHyb_2035, CarGasolineHyb_2040 + CarDieselHyb_2040, CarGasolineHyb_2045 + CarDieselHyb_2045, CarGasolineHyb_2050 + CarDieselHyb_2050]\n", + "Car_Electric = [CarElectric_2020, CarElectric_2025, CarElectric_2030, CarElectric_2035, CarElectric_2040, CarElectric_2045, CarElectric_2050]\n", + "\n", + "plt.bar(years, Car_Conventional, label='Conventional', color='blue')\n", + "plt.bar(years, Car_Hybrid, label='Hybrid', color='red', bottom=Car_Conventional)\n", + "plt.bar(years, Car_Electric, label='Electric', color='green', bottom=[sum(x) for x in zip(Car_Conventional, Car_Hybrid)])\n", + "plt.title('Cars')\n", + "plt.xlabel('Year')\n", + "plt.ylabel('Millions of vehicles')\n", + "plt.legend()\n", + "plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))" ] } ], @@ -426,7 +6965,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.11" + "version": "3.10.14" }, "vscode": { "interpreter": { diff --git a/notebooks/scenarios_from_results.ipynb b/notebooks/scenarios_from_results.ipynb index 418802c..108d1f9 100644 --- a/notebooks/scenarios_from_results.ipynb +++ b/notebooks/scenarios_from_results.ipynb @@ -89,7 +89,7 @@ "import pandas as pd\n", "\n", "# Output Index config file path\n", - "excel_path = \"../data/input/openMASTER_Data.xlsm\" \n", + "excel_path = \"../data/input/openMASTER_Data_2050_v1_STPathway.xlsx\" \n", "# Loading the Output Index config\n", "index_config = pd.read_excel(excel_path, sheet_name=\"Output\")\n", "\n", @@ -150,16 +150,16 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 84, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "'\\n# Scenario Index File Path\\nscenario_index_path = \"../scenarios/scenarios_index.csv\"\\n\\n# Adding the new scenario to the index of scenarios\\nif os.path.exists(scenario_index_path):\\n \\n # If the file exists, load it into a DataFrame\\n df_scenario_index = pd.read_csv(scenario_index_path)\\n df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True)\\nelse:\\n # If the file doesn\\'t exist, create a new DataFrame with the desired columns\\n df_scenario_index = df_scenario_info.copy()\\n\\ndf_scenario_index.to_csv(scenario_index_path, index=False)\\n'" + "'\\n# Scenario Index File Path\\nscenario_index_path = \"../scenarios/scenarios_index.csv\"\\n\\n# Adding the new scenario to the index of scenarios+\\nif os.path.exists(scenario_index_path):\\n \\n # If the file exists, load it into a DataFrame\\n df_scenario_index = pd.read_csv(scenario_index_path)\\n df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True)\\nelse:\\n # If the file doesn\\'t exist, create a new DataFrame with the desired columns\\n df_scenario_index = df_scenario_info.copy()\\n\\ndf_scenario_index.to_csv(scenario_index_path, index=False)\\n'" ] }, - "execution_count": 6, + "execution_count": 84, "metadata": {}, "output_type": "execute_result" } @@ -169,7 +169,7 @@ "# Scenario Index File Path\n", "scenario_index_path = \"../scenarios/scenarios_index.csv\"\n", "\n", - "# Adding the new scenario to the index of scenarios\n", + "# Adding the new scenario to the index of scenarios+\n", "if os.path.exists(scenario_index_path):\n", " \n", " # If the file exists, load it into a DataFrame\n", @@ -200,7 +200,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.11" + "version": "3.10.14" }, "vscode": { "interpreter": { diff --git a/pyproject.toml b/pyproject.toml index 9e4fb99..0b968cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,7 @@ classifiers = [ "Programming Language :: Python :: 3", ] dependencies = [ - "pandas~=1.5", + "pandas>=1.5", "pyomo~=6.5", "openpyxl~=3.1", "matplotlib~=3.7", diff --git "a/scenarios/Avance_tecnol\303\263gico/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Avance_tecnol\303\263gico/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git "a/scenarios/Avance_tecnol\303\263gico/data/input/Data_Industrial.xlsx" "b/scenarios/Avance_tecnol\303\263gico/data/input/Data_Industrial.xlsx" new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/data/input/Data_Industrial.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git "a/scenarios/Avance_tecnol\303\263gico/data/input/Data_Residential.xlsx" "b/scenarios/Avance_tecnol\303\263gico/data/input/Data_Residential.xlsx" new file mode 100644 index 0000000..99fcdce --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/data/input/Data_Residential.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git "a/scenarios/Avance_tecnol\303\263gico/data/input/costs_correl.csv" "b/scenarios/Avance_tecnol\303\263gico/data/input/costs_correl.csv" new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/data/input/costs_correl.csv" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git "a/scenarios/Avance_tecnol\303\263gico/data/input/costs_correl_orig.csv" "b/scenarios/Avance_tecnol\303\263gico/data/input/costs_correl_orig.csv" new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/data/input/costs_correl_orig.csv" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git "a/scenarios/Avance_tecnol\303\263gico/data/input/covar.xlsx" "b/scenarios/Avance_tecnol\303\263gico/data/input/covar.xlsx" new file mode 100644 index 0000000..67b924c --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/data/input/covar.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git "a/scenarios/Avance_tecnol\303\263gico/data/input/mean.csv" "b/scenarios/Avance_tecnol\303\263gico/data/input/mean.csv" new file mode 100644 index 0000000..a18935e --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/data/input/mean.csv" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git "a/scenarios/Avance_tecnol\303\263gico/data/input/openMASTER_Data.xlsx" "b/scenarios/Avance_tecnol\303\263gico/data/input/openMASTER_Data.xlsx" new file mode 100644 index 0000000..3af6db2 --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/data/input/openMASTER_Data.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aa835f53b812ab8f1302872a1732f7f135886b422c75e8f9118cc33fd7291c6c +size 1265704 diff --git "a/scenarios/Avance_tecnol\303\263gico/data/input/openMASTER_Data_.xlsx" "b/scenarios/Avance_tecnol\303\263gico/data/input/openMASTER_Data_.xlsx" new file mode 100644 index 0000000..158d6ae --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/data/input/openMASTER_Data_.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8be85bbef3219b5bbd6970e59b80db186750f839ee5eae0eb1872e89a1f5f10b +size 1262226 diff --git "a/scenarios/Avance_tecnol\303\263gico/data/input/openMASTER_Data_Caso_Avance_Tecnol\303\263gico.xlsx" "b/scenarios/Avance_tecnol\303\263gico/data/input/openMASTER_Data_Caso_Avance_Tecnol\303\263gico.xlsx" new file mode 100644 index 0000000..993bfea --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/data/input/openMASTER_Data_Caso_Avance_Tecnol\303\263gico.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bf9f6b27e69abbdd2476055329ed00684a8b151b96bef5669c42d6e0cc413bf3 +size 1265882 diff --git "a/scenarios/Avance_tecnol\303\263gico/data/input/openMASTER_Data_Caso_Estancamiento.xlsx" "b/scenarios/Avance_tecnol\303\263gico/data/input/openMASTER_Data_Caso_Estancamiento.xlsx" new file mode 100644 index 0000000..ad60d9f --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/data/input/openMASTER_Data_Caso_Estancamiento.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a74c8bcf468f645e57055314d7426fc8dae5eef0ac39e1e64c6689986e86ee78 +size 1265746 diff --git "a/scenarios/Avance_tecnol\303\263gico/data/input/openMASTER_Data_Caso_Mantenimiento_de_Pol\303\255ticas_Descarb.xlsx" "b/scenarios/Avance_tecnol\303\263gico/data/input/openMASTER_Data_Caso_Mantenimiento_de_Pol\303\255ticas_Descarb.xlsx" new file mode 100644 index 0000000..531b883 --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/data/input/openMASTER_Data_Caso_Mantenimiento_de_Pol\303\255ticas_Descarb.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4055e80df075ab5f57afe812bc520bc72469c6a0a47bffcc28801e871998496b +size 1265815 diff --git "a/scenarios/Avance_tecnol\303\263gico/data/output/Results.xlsx" "b/scenarios/Avance_tecnol\303\263gico/data/output/Results.xlsx" new file mode 100644 index 0000000..983f86a --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/data/output/Results.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git "a/scenarios/Avance_tecnol\303\263gico/src/openMASTER/Graphing_Tool/main.py" "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/Graphing_Tool/main.py" new file mode 100644 index 0000000..f60303a --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/Graphing_Tool/main.py" @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git "a/scenarios/Avance_tecnol\303\263gico/src/openMASTER/Graphing_Tool/openMASTER.png" "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/Graphing_Tool/openMASTER.png" new file mode 100644 index 0000000..436ce91 Binary files /dev/null and "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/Graphing_Tool/openMASTER.png" differ diff --git "a/scenarios/Avance_tecnol\303\263gico/src/openMASTER/Graphing_Tool/openMASTER_nobg.png" "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/Graphing_Tool/openMASTER_nobg.png" new file mode 100644 index 0000000..2840568 Binary files /dev/null and "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/Graphing_Tool/openMASTER_nobg.png" differ diff --git "a/scenarios/Avance_tecnol\303\263gico/src/openMASTER/Graphing_Tool/sankey.py" "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/Graphing_Tool/sankey.py" new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/Graphing_Tool/sankey.py" @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git "a/scenarios/Avance_tecnol\303\263gico/src/openMASTER/Graphing_Tool/sankey_description.txt" "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/Graphing_Tool/sankey_description.txt" new file mode 100644 index 0000000..40536f2 --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/Graphing_Tool/sankey_description.txt" @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git "a/scenarios/Avance_tecnol\303\263gico/src/openMASTER/GurobiShell.py" "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/GurobiShell.py" new file mode 100644 index 0000000..5e89353 --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/GurobiShell.py" @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git "a/scenarios/Avance_tecnol\303\263gico/src/openMASTER/__init__.py" "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/__init__.py" new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/__init__.py" @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git "a/scenarios/Avance_tecnol\303\263gico/src/openMASTER/const.py" "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/const.py" new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/const.py" @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git "a/scenarios/Avance_tecnol\303\263gico/src/openMASTER/execute_sankey.py" "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/execute_sankey.py" new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/execute_sankey.py" @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git "a/scenarios/Avance_tecnol\303\263gico/src/openMASTER/loader.py" "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/loader.py" new file mode 100644 index 0000000..3c665df --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/loader.py" @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git "a/scenarios/Avance_tecnol\303\263gico/src/openMASTER/model.py" "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/model.py" new file mode 100644 index 0000000..a93979e --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/model.py" @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git "a/scenarios/Avance_tecnol\303\263gico/src/openMASTER/output_data.py" "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/output_data.py" new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/output_data.py" @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git "a/scenarios/Avance_tecnol\303\263gico/src/openMASTER/scenarios.py" "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/scenarios.py" new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/scenarios.py" @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git "a/scenarios/Avance_tecnol\303\263gico/src/openMASTER/utils.py" "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/utils.py" new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ "b/scenarios/Avance_tecnol\303\263gico/src/openMASTER/utils.py" @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Correl_-0_5/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Correl_-0_5/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Correl_-0_5/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Correl_-0_5/data/input/Data_Industrial.xlsx b/scenarios/Correl_-0_5/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Correl_-0_5/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Correl_-0_5/data/input/Data_Residential.xlsx b/scenarios/Correl_-0_5/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Correl_-0_5/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Correl_-0_5/data/input/costs_correl.csv b/scenarios/Correl_-0_5/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Correl_-0_5/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Correl_-0_5/data/input/costs_correl_orig.csv b/scenarios/Correl_-0_5/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Correl_-0_5/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Correl_-0_5/data/input/covar.xlsx b/scenarios/Correl_-0_5/data/input/covar.xlsx new file mode 100644 index 0000000..2ed4e21 --- /dev/null +++ b/scenarios/Correl_-0_5/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8beb3cf6919a08e254dfd0212a39f1173ec3205e0d3af273bb9711a8c2ace721 +size 152367 diff --git a/scenarios/Correl_-0_5/data/input/mean.csv b/scenarios/Correl_-0_5/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Correl_-0_5/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Correl_-0_5/data/input/openMASTER_Data.xlsx b/scenarios/Correl_-0_5/data/input/openMASTER_Data.xlsx new file mode 100644 index 0000000..765f2a8 --- /dev/null +++ b/scenarios/Correl_-0_5/data/input/openMASTER_Data.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777981ca653bf44d8ac3863c49e1ab579c60cd8b891a1243c89b21e0b5677e18 +size 1255467 diff --git a/scenarios/Correl_-0_5/data/input/openMASTER_Data_.xlsx b/scenarios/Correl_-0_5/data/input/openMASTER_Data_.xlsx new file mode 100644 index 0000000..158d6ae --- /dev/null +++ b/scenarios/Correl_-0_5/data/input/openMASTER_Data_.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8be85bbef3219b5bbd6970e59b80db186750f839ee5eae0eb1872e89a1f5f10b +size 1262226 diff --git "a/scenarios/Correl_-0_5/data/input/openMASTER_Data_Caso_Avance_Tecnol\303\263gico.xlsx" "b/scenarios/Correl_-0_5/data/input/openMASTER_Data_Caso_Avance_Tecnol\303\263gico.xlsx" new file mode 100644 index 0000000..993bfea --- /dev/null +++ "b/scenarios/Correl_-0_5/data/input/openMASTER_Data_Caso_Avance_Tecnol\303\263gico.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bf9f6b27e69abbdd2476055329ed00684a8b151b96bef5669c42d6e0cc413bf3 +size 1265882 diff --git a/scenarios/Correl_-0_5/data/input/openMASTER_Data_Caso_Estancamiento.xlsx b/scenarios/Correl_-0_5/data/input/openMASTER_Data_Caso_Estancamiento.xlsx new file mode 100644 index 0000000..ad60d9f --- /dev/null +++ b/scenarios/Correl_-0_5/data/input/openMASTER_Data_Caso_Estancamiento.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a74c8bcf468f645e57055314d7426fc8dae5eef0ac39e1e64c6689986e86ee78 +size 1265746 diff --git "a/scenarios/Correl_-0_5/data/input/openMASTER_Data_Caso_Mantenimiento_de_Pol\303\255ticas_Descarb.xlsx" "b/scenarios/Correl_-0_5/data/input/openMASTER_Data_Caso_Mantenimiento_de_Pol\303\255ticas_Descarb.xlsx" new file mode 100644 index 0000000..531b883 --- /dev/null +++ "b/scenarios/Correl_-0_5/data/input/openMASTER_Data_Caso_Mantenimiento_de_Pol\303\255ticas_Descarb.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4055e80df075ab5f57afe812bc520bc72469c6a0a47bffcc28801e871998496b +size 1265815 diff --git a/scenarios/Correl_-0_5/data/input/openMASTER_Data_github.xlsx b/scenarios/Correl_-0_5/data/input/openMASTER_Data_github.xlsx new file mode 100644 index 0000000..347e924 --- /dev/null +++ b/scenarios/Correl_-0_5/data/input/openMASTER_Data_github.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:89ce24d51f82e118ddbe033182ebb2a4de3c462ff7fd7c327334db58506175ee +size 1190308 diff --git a/scenarios/Correl_-0_5/data/output/Results.xlsx b/scenarios/Correl_-0_5/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Correl_-0_5/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Correl_-0_5/src/openMASTER/Graphing_Tool/main.py b/scenarios/Correl_-0_5/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Correl_-0_5/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Correl_-0_5/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Correl_-0_5/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Correl_-0_5/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Correl_-0_5/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Correl_-0_5/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Correl_-0_5/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Correl_-0_5/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Correl_-0_5/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Correl_-0_5/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Correl_-0_5/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Correl_-0_5/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Correl_-0_5/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Correl_-0_5/src/openMASTER/GurobiShell.py b/scenarios/Correl_-0_5/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Correl_-0_5/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Correl_-0_5/src/openMASTER/__init__.py b/scenarios/Correl_-0_5/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Correl_-0_5/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Correl_-0_5/src/openMASTER/const.py b/scenarios/Correl_-0_5/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Correl_-0_5/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Correl_-0_5/src/openMASTER/execute_sankey.py b/scenarios/Correl_-0_5/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Correl_-0_5/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Correl_-0_5/src/openMASTER/loader.py b/scenarios/Correl_-0_5/src/openMASTER/loader.py new file mode 100644 index 0000000..70de7be --- /dev/null +++ b/scenarios/Correl_-0_5/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Correl_-0_5/src/openMASTER/model.py b/scenarios/Correl_-0_5/src/openMASTER/model.py new file mode 100644 index 0000000..8d4b333 --- /dev/null +++ b/scenarios/Correl_-0_5/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + 'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + 'EQ_UncCost_Cher', + 'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + 'EQ_InvCostCE_Unc', + 'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + #'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + #'EQ_InvCostCE', + 'EQ_InvCostST', + #'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + #'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + 'EQ_EmiCO2CapTra', + 'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + 'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Correl_-0_5/src/openMASTER/output_data.py b/scenarios/Correl_-0_5/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Correl_-0_5/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Correl_-0_5/src/openMASTER/scenarios.py b/scenarios/Correl_-0_5/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Correl_-0_5/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Correl_-0_5/src/openMASTER/utils.py b/scenarios/Correl_-0_5/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Correl_-0_5/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Correl_0_0/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Correl_0_0/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Correl_0_0/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Correl_0_0/data/input/Data_Industrial.xlsx b/scenarios/Correl_0_0/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Correl_0_0/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Correl_0_0/data/input/Data_Residential.xlsx b/scenarios/Correl_0_0/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Correl_0_0/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Correl_0_0/data/input/costs_correl.csv b/scenarios/Correl_0_0/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Correl_0_0/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Correl_0_0/data/input/costs_correl_orig.csv b/scenarios/Correl_0_0/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Correl_0_0/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Correl_0_0/data/input/covar.xlsx b/scenarios/Correl_0_0/data/input/covar.xlsx new file mode 100644 index 0000000..5825077 --- /dev/null +++ b/scenarios/Correl_0_0/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1069bea23f3abf1826d77dbae7bc114ed1108ba314a2e3f95abf17beaf873677 +size 78936 diff --git a/scenarios/Correl_0_0/data/input/mean.csv b/scenarios/Correl_0_0/data/input/mean.csv new file mode 100644 index 0000000..bac06d6 --- /dev/null +++ b/scenarios/Correl_0_0/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0e988d4ab742f3dc70b0cf8b3682ca05d4916b0d09e3edb857d6b1383215025e +size 939 diff --git a/scenarios/Correl_0_0/data/input/openMASTER_Data.xlsx b/scenarios/Correl_0_0/data/input/openMASTER_Data.xlsx new file mode 100644 index 0000000..68005c8 --- /dev/null +++ b/scenarios/Correl_0_0/data/input/openMASTER_Data.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fd013af827f98d412b8970a2efa0b45b54ffb78b79f5a8da640a90c0b8cc4aa8 +size 1255496 diff --git a/scenarios/Correl_0_0/data/input/openMASTER_Data_.xlsx b/scenarios/Correl_0_0/data/input/openMASTER_Data_.xlsx new file mode 100644 index 0000000..158d6ae --- /dev/null +++ b/scenarios/Correl_0_0/data/input/openMASTER_Data_.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8be85bbef3219b5bbd6970e59b80db186750f839ee5eae0eb1872e89a1f5f10b +size 1262226 diff --git "a/scenarios/Correl_0_0/data/input/openMASTER_Data_Caso_Avance_Tecnol\303\263gico.xlsx" "b/scenarios/Correl_0_0/data/input/openMASTER_Data_Caso_Avance_Tecnol\303\263gico.xlsx" new file mode 100644 index 0000000..993bfea --- /dev/null +++ "b/scenarios/Correl_0_0/data/input/openMASTER_Data_Caso_Avance_Tecnol\303\263gico.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bf9f6b27e69abbdd2476055329ed00684a8b151b96bef5669c42d6e0cc413bf3 +size 1265882 diff --git a/scenarios/Correl_0_0/data/input/openMASTER_Data_Caso_Estancamiento.xlsx b/scenarios/Correl_0_0/data/input/openMASTER_Data_Caso_Estancamiento.xlsx new file mode 100644 index 0000000..ad60d9f --- /dev/null +++ b/scenarios/Correl_0_0/data/input/openMASTER_Data_Caso_Estancamiento.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a74c8bcf468f645e57055314d7426fc8dae5eef0ac39e1e64c6689986e86ee78 +size 1265746 diff --git "a/scenarios/Correl_0_0/data/input/openMASTER_Data_Caso_Mantenimiento_de_Pol\303\255ticas_Descarb - copia.xlsx" "b/scenarios/Correl_0_0/data/input/openMASTER_Data_Caso_Mantenimiento_de_Pol\303\255ticas_Descarb - copia.xlsx" new file mode 100644 index 0000000..531b883 --- /dev/null +++ "b/scenarios/Correl_0_0/data/input/openMASTER_Data_Caso_Mantenimiento_de_Pol\303\255ticas_Descarb - copia.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4055e80df075ab5f57afe812bc520bc72469c6a0a47bffcc28801e871998496b +size 1265815 diff --git a/scenarios/Correl_0_0/data/input/openMASTER_Data_github.xlsx b/scenarios/Correl_0_0/data/input/openMASTER_Data_github.xlsx new file mode 100644 index 0000000..347e924 --- /dev/null +++ b/scenarios/Correl_0_0/data/input/openMASTER_Data_github.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:89ce24d51f82e118ddbe033182ebb2a4de3c462ff7fd7c327334db58506175ee +size 1190308 diff --git a/scenarios/Correl_0_0/data/output/Results.xlsx b/scenarios/Correl_0_0/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Correl_0_0/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Correl_0_0/src/openMASTER/Graphing_Tool/main.py b/scenarios/Correl_0_0/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Correl_0_0/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Correl_0_0/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Correl_0_0/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Correl_0_0/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Correl_0_0/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Correl_0_0/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Correl_0_0/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Correl_0_0/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Correl_0_0/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Correl_0_0/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Correl_0_0/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Correl_0_0/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Correl_0_0/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Correl_0_0/src/openMASTER/GurobiShell.py b/scenarios/Correl_0_0/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Correl_0_0/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Correl_0_0/src/openMASTER/__init__.py b/scenarios/Correl_0_0/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Correl_0_0/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Correl_0_0/src/openMASTER/const.py b/scenarios/Correl_0_0/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Correl_0_0/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Correl_0_0/src/openMASTER/execute_sankey.py b/scenarios/Correl_0_0/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Correl_0_0/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Correl_0_0/src/openMASTER/loader.py b/scenarios/Correl_0_0/src/openMASTER/loader.py new file mode 100644 index 0000000..70de7be --- /dev/null +++ b/scenarios/Correl_0_0/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Correl_0_0/src/openMASTER/model.py b/scenarios/Correl_0_0/src/openMASTER/model.py new file mode 100644 index 0000000..049cdec --- /dev/null +++ b/scenarios/Correl_0_0/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.f,m.sUnc, within=Reals, doc = '') + m.pAlpha_do = Param(m.f,m.sUnc, within=Reals, doc = '') + m.pRest = Param(m.f,m.sUnc, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[f,sPE] for f in m.f1) + sum(m.pRest[f,sPE] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[f,sCE] for f in m.f1) + sum(m.pRest[f,sCE] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[f1,sPE] - m.pAlpha_do[f1,sPE]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[f1,sCE] - m.pAlpha_do[f1,sCE]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + 'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + 'EQ_InvCostCE_Unc', + 'EQ_OpCost_Unc', + + 'EQ_UncCost_Bert', + 'EQ_UncCost_Bert2', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + #'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + #'EQ_InvCostCE', + 'EQ_InvCostST', + #'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + #'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + 'EQ_EmiCO2CapTra', + 'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + 'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Correl_0_0/src/openMASTER/output_data.py b/scenarios/Correl_0_0/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Correl_0_0/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Correl_0_0/src/openMASTER/scenarios.py b/scenarios/Correl_0_0/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Correl_0_0/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Correl_0_0/src/openMASTER/utils.py b/scenarios/Correl_0_0/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Correl_0_0/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Correl_0_0_vOrig/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Correl_0_0_vOrig/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..43906f1 --- /dev/null +++ "b/scenarios/Correl_0_0_vOrig/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8d252f956de2b759cf692f0d41de96afce2fee398aa1145914de34fc5af22602 +size 2095758 diff --git a/scenarios/Correl_0_0_vOrig/data/input/Data_Industrial.xlsx b/scenarios/Correl_0_0_vOrig/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Correl_0_0_vOrig/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Correl_0_0_vOrig/data/input/Data_Residential.xlsx b/scenarios/Correl_0_0_vOrig/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Correl_0_0_vOrig/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Correl_0_0_vOrig/data/input/costs_correl.csv b/scenarios/Correl_0_0_vOrig/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Correl_0_0_vOrig/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Correl_0_0_vOrig/data/input/costs_correl_orig.csv b/scenarios/Correl_0_0_vOrig/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Correl_0_0_vOrig/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Correl_0_0_vOrig/data/input/covar.xlsx b/scenarios/Correl_0_0_vOrig/data/input/covar.xlsx new file mode 100644 index 0000000..94378fa --- /dev/null +++ b/scenarios/Correl_0_0_vOrig/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:41a14e8097dad265ce7c6e24c4ebebbe7f1c5055bbae7625545ca09d121b1c9f +size 78952 diff --git a/scenarios/Correl_0_0_vOrig/data/input/mean.csv b/scenarios/Correl_0_0_vOrig/data/input/mean.csv new file mode 100644 index 0000000..2fff9e5 --- /dev/null +++ b/scenarios/Correl_0_0_vOrig/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a91b8faab482cbdc4c145ae040244c3ffae0448ccb16ab87568d269b2dd1f0e3 +size 938 diff --git a/scenarios/Correl_0_0_vOrig/data/input/openMASTER_Data.xlsx b/scenarios/Correl_0_0_vOrig/data/input/openMASTER_Data.xlsx new file mode 100644 index 0000000..fafe2d3 --- /dev/null +++ b/scenarios/Correl_0_0_vOrig/data/input/openMASTER_Data.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c00b1b313cb9cd38140278bc19cfbc855396b7cf3da1712f4c1e1d73ac5176df +size 1255396 diff --git a/scenarios/Correl_0_0_vOrig/data/output/Results.xlsx b/scenarios/Correl_0_0_vOrig/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Correl_0_0_vOrig/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git "a/scenarios/Correl_0_5/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Correl_0_5/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Correl_0_5/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Correl_0_5/data/input/Data_Industrial.xlsx b/scenarios/Correl_0_5/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Correl_0_5/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Correl_0_5/data/input/Data_Residential.xlsx b/scenarios/Correl_0_5/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Correl_0_5/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Correl_0_5/data/input/costs_correl.csv b/scenarios/Correl_0_5/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Correl_0_5/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Correl_0_5/data/input/costs_correl_orig.csv b/scenarios/Correl_0_5/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Correl_0_5/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Correl_0_5/data/input/covar.xlsx b/scenarios/Correl_0_5/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Correl_0_5/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Correl_0_5/data/input/mean.csv b/scenarios/Correl_0_5/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Correl_0_5/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Correl_0_5/data/input/openMASTER_Data.xlsx b/scenarios/Correl_0_5/data/input/openMASTER_Data.xlsx new file mode 100644 index 0000000..765f2a8 --- /dev/null +++ b/scenarios/Correl_0_5/data/input/openMASTER_Data.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777981ca653bf44d8ac3863c49e1ab579c60cd8b891a1243c89b21e0b5677e18 +size 1255467 diff --git a/scenarios/Correl_0_5/data/input/openMASTER_Data_.xlsx b/scenarios/Correl_0_5/data/input/openMASTER_Data_.xlsx new file mode 100644 index 0000000..158d6ae --- /dev/null +++ b/scenarios/Correl_0_5/data/input/openMASTER_Data_.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8be85bbef3219b5bbd6970e59b80db186750f839ee5eae0eb1872e89a1f5f10b +size 1262226 diff --git "a/scenarios/Correl_0_5/data/input/openMASTER_Data_Caso_Avance_Tecnol\303\263gico.xlsx" "b/scenarios/Correl_0_5/data/input/openMASTER_Data_Caso_Avance_Tecnol\303\263gico.xlsx" new file mode 100644 index 0000000..993bfea --- /dev/null +++ "b/scenarios/Correl_0_5/data/input/openMASTER_Data_Caso_Avance_Tecnol\303\263gico.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bf9f6b27e69abbdd2476055329ed00684a8b151b96bef5669c42d6e0cc413bf3 +size 1265882 diff --git a/scenarios/Correl_0_5/data/input/openMASTER_Data_Caso_Estancamiento.xlsx b/scenarios/Correl_0_5/data/input/openMASTER_Data_Caso_Estancamiento.xlsx new file mode 100644 index 0000000..ad60d9f --- /dev/null +++ b/scenarios/Correl_0_5/data/input/openMASTER_Data_Caso_Estancamiento.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a74c8bcf468f645e57055314d7426fc8dae5eef0ac39e1e64c6689986e86ee78 +size 1265746 diff --git "a/scenarios/Correl_0_5/data/input/openMASTER_Data_Caso_Mantenimiento_de_Pol\303\255ticas_Descarb.xlsx" "b/scenarios/Correl_0_5/data/input/openMASTER_Data_Caso_Mantenimiento_de_Pol\303\255ticas_Descarb.xlsx" new file mode 100644 index 0000000..531b883 --- /dev/null +++ "b/scenarios/Correl_0_5/data/input/openMASTER_Data_Caso_Mantenimiento_de_Pol\303\255ticas_Descarb.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4055e80df075ab5f57afe812bc520bc72469c6a0a47bffcc28801e871998496b +size 1265815 diff --git a/scenarios/Correl_0_5/data/input/openMASTER_Data_github.xlsx b/scenarios/Correl_0_5/data/input/openMASTER_Data_github.xlsx new file mode 100644 index 0000000..347e924 --- /dev/null +++ b/scenarios/Correl_0_5/data/input/openMASTER_Data_github.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:89ce24d51f82e118ddbe033182ebb2a4de3c462ff7fd7c327334db58506175ee +size 1190308 diff --git a/scenarios/Correl_0_5/data/output/Results.xlsx b/scenarios/Correl_0_5/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Correl_0_5/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Correl_0_5/src/openMASTER/Graphing_Tool/main.py b/scenarios/Correl_0_5/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Correl_0_5/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Correl_0_5/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Correl_0_5/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Correl_0_5/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Correl_0_5/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Correl_0_5/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Correl_0_5/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Correl_0_5/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Correl_0_5/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Correl_0_5/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Correl_0_5/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Correl_0_5/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Correl_0_5/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Correl_0_5/src/openMASTER/GurobiShell.py b/scenarios/Correl_0_5/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Correl_0_5/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Correl_0_5/src/openMASTER/__init__.py b/scenarios/Correl_0_5/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Correl_0_5/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Correl_0_5/src/openMASTER/const.py b/scenarios/Correl_0_5/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Correl_0_5/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Correl_0_5/src/openMASTER/execute_sankey.py b/scenarios/Correl_0_5/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Correl_0_5/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Correl_0_5/src/openMASTER/loader.py b/scenarios/Correl_0_5/src/openMASTER/loader.py new file mode 100644 index 0000000..70de7be --- /dev/null +++ b/scenarios/Correl_0_5/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Correl_0_5/src/openMASTER/model.py b/scenarios/Correl_0_5/src/openMASTER/model.py new file mode 100644 index 0000000..8d4b333 --- /dev/null +++ b/scenarios/Correl_0_5/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + 'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + 'EQ_UncCost_Cher', + 'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + 'EQ_InvCostCE_Unc', + 'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + #'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + #'EQ_InvCostCE', + 'EQ_InvCostST', + #'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + #'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + 'EQ_EmiCO2CapTra', + 'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + 'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Correl_0_5/src/openMASTER/output_data.py b/scenarios/Correl_0_5/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Correl_0_5/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Correl_0_5/src/openMASTER/scenarios.py b/scenarios/Correl_0_5/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Correl_0_5/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Correl_0_5/src/openMASTER/utils.py b/scenarios/Correl_0_5/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Correl_0_5/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Correl_24_06_2024-15_27_12/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Correl_24_06_2024-15_27_12/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Correl_24_06_2024-15_27_12/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Correl_24_06_2024-15_27_12/data/input/Data_Industrial.xlsx b/scenarios/Correl_24_06_2024-15_27_12/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Correl_24_06_2024-15_27_12/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Correl_24_06_2024-15_27_12/data/input/Data_Residential.xlsx b/scenarios/Correl_24_06_2024-15_27_12/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Correl_24_06_2024-15_27_12/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Correl_24_06_2024-15_27_12/data/input/costs_correl.csv b/scenarios/Correl_24_06_2024-15_27_12/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Correl_24_06_2024-15_27_12/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Correl_24_06_2024-15_27_12/data/input/costs_correl_orig.csv b/scenarios/Correl_24_06_2024-15_27_12/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Correl_24_06_2024-15_27_12/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Correl_24_06_2024-15_27_12/data/input/covar.xlsx b/scenarios/Correl_24_06_2024-15_27_12/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Correl_24_06_2024-15_27_12/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Correl_24_06_2024-15_27_12/data/input/mean.csv b/scenarios/Correl_24_06_2024-15_27_12/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Correl_24_06_2024-15_27_12/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Correl_24_06_2024-15_27_12/data/input/openMASTER_Data.xlsx b/scenarios/Correl_24_06_2024-15_27_12/data/input/openMASTER_Data.xlsx new file mode 100644 index 0000000..8689318 --- /dev/null +++ b/scenarios/Correl_24_06_2024-15_27_12/data/input/openMASTER_Data.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8b5a0aa4617c5b59340c07391c623b5880ad5e203974630821116b00d318a8b9 +size 1259726 diff --git a/scenarios/Correl_24_06_2024-15_27_12/data/output/Results.xlsx b/scenarios/Correl_24_06_2024-15_27_12/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Correl_24_06_2024-15_27_12/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/Graphing_Tool/main.py b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/GurobiShell.py b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/__init__.py b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/const.py b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/execute_sankey.py b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/loader.py b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/model.py b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/output_data.py b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/scenarios.py b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/utils.py b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Correl_24_06_2024-15_27_12/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Correl_25_06_2024-10_06_32/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Correl_25_06_2024-10_06_32/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Correl_25_06_2024-10_06_32/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Correl_25_06_2024-10_06_32/data/input/Data_Industrial.xlsx b/scenarios/Correl_25_06_2024-10_06_32/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Correl_25_06_2024-10_06_32/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Correl_25_06_2024-10_06_32/data/input/Data_Residential.xlsx b/scenarios/Correl_25_06_2024-10_06_32/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Correl_25_06_2024-10_06_32/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Correl_25_06_2024-10_06_32/data/input/costs_correl.csv b/scenarios/Correl_25_06_2024-10_06_32/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Correl_25_06_2024-10_06_32/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Correl_25_06_2024-10_06_32/data/input/costs_correl_orig.csv b/scenarios/Correl_25_06_2024-10_06_32/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Correl_25_06_2024-10_06_32/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Correl_25_06_2024-10_06_32/data/input/covar.xlsx b/scenarios/Correl_25_06_2024-10_06_32/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Correl_25_06_2024-10_06_32/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Correl_25_06_2024-10_06_32/data/input/mean.csv b/scenarios/Correl_25_06_2024-10_06_32/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Correl_25_06_2024-10_06_32/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Correl_25_06_2024-10_06_32/data/input/openMASTER_Data.xlsx b/scenarios/Correl_25_06_2024-10_06_32/data/input/openMASTER_Data.xlsx new file mode 100644 index 0000000..23f3413 --- /dev/null +++ b/scenarios/Correl_25_06_2024-10_06_32/data/input/openMASTER_Data.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c052f3c930cfb13a789779de92f4eb105565dd7d374740746f2b16aeea1171f8 +size 1260538 diff --git a/scenarios/Correl_25_06_2024-10_06_32/data/output/Results.xlsx b/scenarios/Correl_25_06_2024-10_06_32/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Correl_25_06_2024-10_06_32/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/Graphing_Tool/main.py b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/GurobiShell.py b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/__init__.py b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/const.py b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/execute_sankey.py b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/loader.py b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/model.py b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/output_data.py b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/scenarios.py b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/utils.py b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Correl_25_06_2024-10_06_32/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Correl_25_06_2024-12_48_35/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Correl_25_06_2024-12_48_35/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Correl_25_06_2024-12_48_35/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Correl_25_06_2024-12_48_35/data/input/Data_Industrial.xlsx b/scenarios/Correl_25_06_2024-12_48_35/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Correl_25_06_2024-12_48_35/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Correl_25_06_2024-12_48_35/data/input/Data_Residential.xlsx b/scenarios/Correl_25_06_2024-12_48_35/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Correl_25_06_2024-12_48_35/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Correl_25_06_2024-12_48_35/data/input/costs_correl.csv b/scenarios/Correl_25_06_2024-12_48_35/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Correl_25_06_2024-12_48_35/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Correl_25_06_2024-12_48_35/data/input/costs_correl_orig.csv b/scenarios/Correl_25_06_2024-12_48_35/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Correl_25_06_2024-12_48_35/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Correl_25_06_2024-12_48_35/data/input/covar.xlsx b/scenarios/Correl_25_06_2024-12_48_35/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Correl_25_06_2024-12_48_35/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Correl_25_06_2024-12_48_35/data/input/mean.csv b/scenarios/Correl_25_06_2024-12_48_35/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Correl_25_06_2024-12_48_35/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Correl_25_06_2024-12_48_35/data/input/openMASTER_Data.xlsx b/scenarios/Correl_25_06_2024-12_48_35/data/input/openMASTER_Data.xlsx new file mode 100644 index 0000000..e56a9a0 --- /dev/null +++ b/scenarios/Correl_25_06_2024-12_48_35/data/input/openMASTER_Data.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cca29bc0ade5c8f529bffe7bd031c6cb3cb47409a466107aa8337fd6a7a23a57 +size 1260835 diff --git a/scenarios/Correl_25_06_2024-12_48_35/data/output/Results.xlsx b/scenarios/Correl_25_06_2024-12_48_35/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Correl_25_06_2024-12_48_35/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/Graphing_Tool/main.py b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/GurobiShell.py b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/__init__.py b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/const.py b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/execute_sankey.py b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/loader.py b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/model.py b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/output_data.py b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/scenarios.py b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/utils.py b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Correl_25_06_2024-12_48_35/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Correl_27_06_2024-10_45_53/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Correl_27_06_2024-10_45_53/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Correl_27_06_2024-10_45_53/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Correl_27_06_2024-10_45_53/data/input/Data_Industrial.xlsx b/scenarios/Correl_27_06_2024-10_45_53/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_45_53/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Correl_27_06_2024-10_45_53/data/input/Data_Residential.xlsx b/scenarios/Correl_27_06_2024-10_45_53/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_45_53/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Correl_27_06_2024-10_45_53/data/input/costs_correl.csv b/scenarios/Correl_27_06_2024-10_45_53/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_45_53/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Correl_27_06_2024-10_45_53/data/input/costs_correl_orig.csv b/scenarios/Correl_27_06_2024-10_45_53/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_45_53/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Correl_27_06_2024-10_45_53/data/input/covar.xlsx b/scenarios/Correl_27_06_2024-10_45_53/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_45_53/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Correl_27_06_2024-10_45_53/data/input/mean.csv b/scenarios/Correl_27_06_2024-10_45_53/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_45_53/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Correl_27_06_2024-10_45_53/data/input/openMASTER_Data.xlsx b/scenarios/Correl_27_06_2024-10_45_53/data/input/openMASTER_Data.xlsx new file mode 100644 index 0000000..8bebf10 --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_45_53/data/input/openMASTER_Data.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:605e0495846062627868537aa21cd1a29b2f09365b28bf1649af5fe54ba0c7d3 +size 1292112 diff --git a/scenarios/Correl_27_06_2024-10_45_53/data/output/Results.xlsx b/scenarios/Correl_27_06_2024-10_45_53/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_45_53/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git "a/scenarios/Correl_27_06_2024-10_46_11/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Correl_27_06_2024-10_46_11/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Correl_27_06_2024-10_46_11/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Correl_27_06_2024-10_46_11/data/input/Data_Industrial.xlsx b/scenarios/Correl_27_06_2024-10_46_11/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_46_11/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Correl_27_06_2024-10_46_11/data/input/Data_Residential.xlsx b/scenarios/Correl_27_06_2024-10_46_11/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_46_11/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Correl_27_06_2024-10_46_11/data/input/costs_correl.csv b/scenarios/Correl_27_06_2024-10_46_11/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_46_11/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Correl_27_06_2024-10_46_11/data/input/costs_correl_orig.csv b/scenarios/Correl_27_06_2024-10_46_11/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_46_11/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Correl_27_06_2024-10_46_11/data/input/covar.xlsx b/scenarios/Correl_27_06_2024-10_46_11/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_46_11/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Correl_27_06_2024-10_46_11/data/input/mean.csv b/scenarios/Correl_27_06_2024-10_46_11/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_46_11/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Correl_27_06_2024-10_46_11/data/input/openMASTER_Data.xlsx b/scenarios/Correl_27_06_2024-10_46_11/data/input/openMASTER_Data.xlsx new file mode 100644 index 0000000..8bebf10 --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_46_11/data/input/openMASTER_Data.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:605e0495846062627868537aa21cd1a29b2f09365b28bf1649af5fe54ba0c7d3 +size 1292112 diff --git a/scenarios/Correl_27_06_2024-10_46_11/data/output/Results.xlsx b/scenarios/Correl_27_06_2024-10_46_11/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_46_11/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/Graphing_Tool/main.py b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/GurobiShell.py b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/__init__.py b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/const.py b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/execute_sankey.py b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/loader.py b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/model.py b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/output_data.py b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/scenarios.py b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/utils.py b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Correl_27_06_2024-10_46_11/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Correl_27_06_2024-12_44_51/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Correl_27_06_2024-12_44_51/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Correl_27_06_2024-12_44_51/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Correl_27_06_2024-12_44_51/data/input/Data_Industrial.xlsx b/scenarios/Correl_27_06_2024-12_44_51/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Correl_27_06_2024-12_44_51/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Correl_27_06_2024-12_44_51/data/input/Data_Residential.xlsx b/scenarios/Correl_27_06_2024-12_44_51/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Correl_27_06_2024-12_44_51/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Correl_27_06_2024-12_44_51/data/input/costs_correl.csv b/scenarios/Correl_27_06_2024-12_44_51/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Correl_27_06_2024-12_44_51/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Correl_27_06_2024-12_44_51/data/input/costs_correl_orig.csv b/scenarios/Correl_27_06_2024-12_44_51/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Correl_27_06_2024-12_44_51/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Correl_27_06_2024-12_44_51/data/input/covar.xlsx b/scenarios/Correl_27_06_2024-12_44_51/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Correl_27_06_2024-12_44_51/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Correl_27_06_2024-12_44_51/data/input/mean.csv b/scenarios/Correl_27_06_2024-12_44_51/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Correl_27_06_2024-12_44_51/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Correl_27_06_2024-12_44_51/data/input/openMASTER_Data.xlsx b/scenarios/Correl_27_06_2024-12_44_51/data/input/openMASTER_Data.xlsx new file mode 100644 index 0000000..431f6a2 --- /dev/null +++ b/scenarios/Correl_27_06_2024-12_44_51/data/input/openMASTER_Data.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ce50f87492bc467478f0d7eaee60bc6efc8a663fe7ee66c19b128f250ed313f4 +size 1291835 diff --git a/scenarios/Correl_27_06_2024-12_44_51/data/output/Results.xlsx b/scenarios/Correl_27_06_2024-12_44_51/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Correl_27_06_2024-12_44_51/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/Graphing_Tool/main.py b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/GurobiShell.py b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/__init__.py b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/const.py b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/execute_sankey.py b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/loader.py b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/model.py b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/output_data.py b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/scenarios.py b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/utils.py b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Correl_27_06_2024-12_44_51/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Correl_RO/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Correl_RO/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Correl_RO/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Correl_RO/data/input/Data_Industrial.xlsx b/scenarios/Correl_RO/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Correl_RO/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Correl_RO/data/input/Data_Residential.xlsx b/scenarios/Correl_RO/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Correl_RO/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Correl_RO/data/input/costs_correl.csv b/scenarios/Correl_RO/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Correl_RO/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Correl_RO/data/input/costs_correl_orig.csv b/scenarios/Correl_RO/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Correl_RO/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Correl_RO/data/input/covar.xlsx b/scenarios/Correl_RO/data/input/covar.xlsx new file mode 100644 index 0000000..5825077 --- /dev/null +++ b/scenarios/Correl_RO/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1069bea23f3abf1826d77dbae7bc114ed1108ba314a2e3f95abf17beaf873677 +size 78936 diff --git a/scenarios/Correl_RO/data/input/mean.csv b/scenarios/Correl_RO/data/input/mean.csv new file mode 100644 index 0000000..bac06d6 --- /dev/null +++ b/scenarios/Correl_RO/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0e988d4ab742f3dc70b0cf8b3682ca05d4916b0d09e3edb857d6b1383215025e +size 939 diff --git a/scenarios/Correl_RO/data/input/openMASTER_Data.xlsx b/scenarios/Correl_RO/data/input/openMASTER_Data.xlsx new file mode 100644 index 0000000..68005c8 --- /dev/null +++ b/scenarios/Correl_RO/data/input/openMASTER_Data.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fd013af827f98d412b8970a2efa0b45b54ffb78b79f5a8da640a90c0b8cc4aa8 +size 1255496 diff --git a/scenarios/Correl_RO/data/input/openMASTER_Data_github.xlsx b/scenarios/Correl_RO/data/input/openMASTER_Data_github.xlsx new file mode 100644 index 0000000..347e924 --- /dev/null +++ b/scenarios/Correl_RO/data/input/openMASTER_Data_github.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:89ce24d51f82e118ddbe033182ebb2a4de3c462ff7fd7c327334db58506175ee +size 1190308 diff --git a/scenarios/Correl_RO/data/output/Results.xlsx b/scenarios/Correl_RO/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Correl_RO/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Correl_RO/src/openMASTER/Graphing_Tool/main.py b/scenarios/Correl_RO/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Correl_RO/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Correl_RO/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Correl_RO/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Correl_RO/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Correl_RO/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Correl_RO/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Correl_RO/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Correl_RO/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Correl_RO/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Correl_RO/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Correl_RO/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Correl_RO/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Correl_RO/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Correl_RO/src/openMASTER/GurobiShell.py b/scenarios/Correl_RO/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Correl_RO/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Correl_RO/src/openMASTER/__init__.py b/scenarios/Correl_RO/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Correl_RO/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Correl_RO/src/openMASTER/const.py b/scenarios/Correl_RO/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Correl_RO/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Correl_RO/src/openMASTER/execute_sankey.py b/scenarios/Correl_RO/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Correl_RO/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Correl_RO/src/openMASTER/loader.py b/scenarios/Correl_RO/src/openMASTER/loader.py new file mode 100644 index 0000000..70de7be --- /dev/null +++ b/scenarios/Correl_RO/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Correl_RO/src/openMASTER/model.py b/scenarios/Correl_RO/src/openMASTER/model.py new file mode 100644 index 0000000..049cdec --- /dev/null +++ b/scenarios/Correl_RO/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.f,m.sUnc, within=Reals, doc = '') + m.pAlpha_do = Param(m.f,m.sUnc, within=Reals, doc = '') + m.pRest = Param(m.f,m.sUnc, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[f,sPE] for f in m.f1) + sum(m.pRest[f,sPE] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[f,sCE] for f in m.f1) + sum(m.pRest[f,sCE] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[f1,sPE] - m.pAlpha_do[f1,sPE]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[f1,sCE] - m.pAlpha_do[f1,sCE]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + 'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + 'EQ_InvCostCE_Unc', + 'EQ_OpCost_Unc', + + 'EQ_UncCost_Bert', + 'EQ_UncCost_Bert2', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + #'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + #'EQ_InvCostCE', + 'EQ_InvCostST', + #'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + #'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + 'EQ_EmiCO2CapTra', + 'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + 'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Correl_RO/src/openMASTER/output_data.py b/scenarios/Correl_RO/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Correl_RO/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Correl_RO/src/openMASTER/scenarios.py b/scenarios/Correl_RO/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Correl_RO/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Correl_RO/src/openMASTER/utils.py b/scenarios/Correl_RO/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Correl_RO/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Descarbonizacion/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Descarbonizacion/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Descarbonizacion/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Descarbonizacion/data/input/Data_Industrial.xlsx b/scenarios/Descarbonizacion/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Descarbonizacion/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Descarbonizacion/data/input/Data_Residential.xlsx b/scenarios/Descarbonizacion/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Descarbonizacion/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Descarbonizacion/data/input/costs_correl.csv b/scenarios/Descarbonizacion/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Descarbonizacion/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Descarbonizacion/data/input/costs_correl_orig.csv b/scenarios/Descarbonizacion/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Descarbonizacion/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Descarbonizacion/data/input/covar.xlsx b/scenarios/Descarbonizacion/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Descarbonizacion/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Descarbonizacion/data/input/mean.csv b/scenarios/Descarbonizacion/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Descarbonizacion/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Descarbonizacion/data/input/openMASTER_Data.xlsx b/scenarios/Descarbonizacion/data/input/openMASTER_Data.xlsx new file mode 100644 index 0000000..dcadf76 --- /dev/null +++ b/scenarios/Descarbonizacion/data/input/openMASTER_Data.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c7d7fc27596c07e6b130cab5adbcb1a5dd6153e308c3fc32e2a1dcff55b40bc6 +size 1265600 diff --git a/scenarios/Descarbonizacion/data/input/openMASTER_Data_.xlsx b/scenarios/Descarbonizacion/data/input/openMASTER_Data_.xlsx new file mode 100644 index 0000000..158d6ae --- /dev/null +++ b/scenarios/Descarbonizacion/data/input/openMASTER_Data_.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8be85bbef3219b5bbd6970e59b80db186750f839ee5eae0eb1872e89a1f5f10b +size 1262226 diff --git "a/scenarios/Descarbonizacion/data/input/openMASTER_Data_Caso_Avance_Tecnol\303\263gico.xlsx" "b/scenarios/Descarbonizacion/data/input/openMASTER_Data_Caso_Avance_Tecnol\303\263gico.xlsx" new file mode 100644 index 0000000..993bfea --- /dev/null +++ "b/scenarios/Descarbonizacion/data/input/openMASTER_Data_Caso_Avance_Tecnol\303\263gico.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bf9f6b27e69abbdd2476055329ed00684a8b151b96bef5669c42d6e0cc413bf3 +size 1265882 diff --git a/scenarios/Descarbonizacion/data/input/openMASTER_Data_Caso_Estancamiento.xlsx b/scenarios/Descarbonizacion/data/input/openMASTER_Data_Caso_Estancamiento.xlsx new file mode 100644 index 0000000..ad60d9f --- /dev/null +++ b/scenarios/Descarbonizacion/data/input/openMASTER_Data_Caso_Estancamiento.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a74c8bcf468f645e57055314d7426fc8dae5eef0ac39e1e64c6689986e86ee78 +size 1265746 diff --git "a/scenarios/Descarbonizacion/data/input/openMASTER_Data_Caso_Mantenimiento_de_Pol\303\255ticas_Descarb - copia.xlsx" "b/scenarios/Descarbonizacion/data/input/openMASTER_Data_Caso_Mantenimiento_de_Pol\303\255ticas_Descarb - copia.xlsx" new file mode 100644 index 0000000..531b883 --- /dev/null +++ "b/scenarios/Descarbonizacion/data/input/openMASTER_Data_Caso_Mantenimiento_de_Pol\303\255ticas_Descarb - copia.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4055e80df075ab5f57afe812bc520bc72469c6a0a47bffcc28801e871998496b +size 1265815 diff --git a/scenarios/Descarbonizacion/data/output/Results.xlsx b/scenarios/Descarbonizacion/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Descarbonizacion/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Descarbonizacion/src/openMASTER/Graphing_Tool/main.py b/scenarios/Descarbonizacion/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Descarbonizacion/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Descarbonizacion/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Descarbonizacion/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Descarbonizacion/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Descarbonizacion/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Descarbonizacion/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Descarbonizacion/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Descarbonizacion/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Descarbonizacion/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Descarbonizacion/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Descarbonizacion/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Descarbonizacion/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Descarbonizacion/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Descarbonizacion/src/openMASTER/GurobiShell.py b/scenarios/Descarbonizacion/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Descarbonizacion/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Descarbonizacion/src/openMASTER/__init__.py b/scenarios/Descarbonizacion/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Descarbonizacion/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Descarbonizacion/src/openMASTER/const.py b/scenarios/Descarbonizacion/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Descarbonizacion/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Descarbonizacion/src/openMASTER/execute_sankey.py b/scenarios/Descarbonizacion/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Descarbonizacion/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Descarbonizacion/src/openMASTER/loader.py b/scenarios/Descarbonizacion/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Descarbonizacion/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Descarbonizacion/src/openMASTER/model.py b/scenarios/Descarbonizacion/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Descarbonizacion/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Descarbonizacion/src/openMASTER/output_data.py b/scenarios/Descarbonizacion/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Descarbonizacion/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Descarbonizacion/src/openMASTER/scenarios.py b/scenarios/Descarbonizacion/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Descarbonizacion/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Descarbonizacion/src/openMASTER/utils.py b/scenarios/Descarbonizacion/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Descarbonizacion/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Det/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Det/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..43906f1 --- /dev/null +++ "b/scenarios/Det/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8d252f956de2b759cf692f0d41de96afce2fee398aa1145914de34fc5af22602 +size 2095758 diff --git a/scenarios/Det/data/input/Data_Industrial.xlsx b/scenarios/Det/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Det/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Det/data/input/Data_Residential.xlsx b/scenarios/Det/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Det/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Det/data/input/costs_correl.csv b/scenarios/Det/data/input/costs_correl.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Det/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Det/data/input/covar.xlsx b/scenarios/Det/data/input/covar.xlsx new file mode 100644 index 0000000..b6f50b3 --- /dev/null +++ b/scenarios/Det/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57ee16e710c623a5cedaf0777ed82f4c424e2f18c7e9f186e47a2dbfc9708c43 +size 78945 diff --git a/scenarios/Det/data/input/mean.csv b/scenarios/Det/data/input/mean.csv new file mode 100644 index 0000000..2fff9e5 --- /dev/null +++ b/scenarios/Det/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a91b8faab482cbdc4c145ae040244c3ffae0448ccb16ab87568d269b2dd1f0e3 +size 938 diff --git a/scenarios/Det/data/input/openMASTER_Data.xlsx b/scenarios/Det/data/input/openMASTER_Data.xlsx new file mode 100644 index 0000000..828fd35 --- /dev/null +++ b/scenarios/Det/data/input/openMASTER_Data.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9afa7b963fa6cd214bd7880978fae1d40ec5386ae62c8d5e50f215d9dd889a31 +size 1223523 diff --git a/scenarios/Det/data/output/Results.xlsx b/scenarios/Det/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Det/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Det/src/openMASTER/Graphing_Tool/main.py b/scenarios/Det/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Det/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Det/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Det/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Det/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Det/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Det/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Det/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Det/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Det/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Det/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Det/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Det/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Det/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Det/src/openMASTER/GurobiShell.py b/scenarios/Det/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Det/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Det/src/openMASTER/__init__.py b/scenarios/Det/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Det/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Det/src/openMASTER/const.py b/scenarios/Det/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Det/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Det/src/openMASTER/execute_sankey.py b/scenarios/Det/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Det/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Det/src/openMASTER/loader.py b/scenarios/Det/src/openMASTER/loader.py new file mode 100644 index 0000000..70de7be --- /dev/null +++ b/scenarios/Det/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Det/src/openMASTER/model.py b/scenarios/Det/src/openMASTER/model.py new file mode 100644 index 0000000..5900584 --- /dev/null +++ b/scenarios/Det/src/openMASTER/model.py @@ -0,0 +1,1835 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.f,m.sUnc, within=Reals, doc = '') + m.pAlpha_do = Param(m.f,m.sUnc, within=Reals, doc = '') + m.pRest = Param(m.f,m.sUnc, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[f,sPE] for f in m.f1) + sum(m.pRest[f,sPE] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[f,sCE] for f in m.f1) + sum(m.pRest[f,sCE] for f in m.fr)) for sCE in m.sCE ) + )) + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[f1,sPE] - m.pAlpha_do[f1,sPE]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[f1,sCE] - m.pAlpha_do[f1,sCE]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + 'EQ_TotalCost_Unc', + 'EQ_UncCost', + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + 'EQ_InvCostCE_Unc', + 'EQ_OpCost_Unc', + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + #'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + #'EQ_InvCostCE', + 'EQ_InvCostST', + #'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + #'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + 'EQ_EmiCO2CapTra', + 'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + 'EQ_EmiCO2CapOth', + 'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Det/src/openMASTER/output_data.py b/scenarios/Det/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Det/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Det/src/openMASTER/scenarios.py b/scenarios/Det/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Det/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Det/src/openMASTER/utils.py b/scenarios/Det/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Det/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Estancamiento/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Estancamiento/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Estancamiento/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Estancamiento/data/input/Data_Industrial.xlsx b/scenarios/Estancamiento/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Estancamiento/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Estancamiento/data/input/Data_Residential.xlsx b/scenarios/Estancamiento/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Estancamiento/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Estancamiento/data/input/costs_correl.csv b/scenarios/Estancamiento/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Estancamiento/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Estancamiento/data/input/costs_correl_orig.csv b/scenarios/Estancamiento/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Estancamiento/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Estancamiento/data/input/covar.xlsx b/scenarios/Estancamiento/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Estancamiento/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Estancamiento/data/input/mean.csv b/scenarios/Estancamiento/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Estancamiento/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Estancamiento/data/input/openMASTER_Data.xlsx b/scenarios/Estancamiento/data/input/openMASTER_Data.xlsx new file mode 100644 index 0000000..1f51f69 --- /dev/null +++ b/scenarios/Estancamiento/data/input/openMASTER_Data.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:046595a3b191efcb4437d82718ae335a7b4bcf38c5c10ae48f6512c3cddbabab +size 1265394 diff --git a/scenarios/Estancamiento/data/input/openMASTER_Data_.xlsx b/scenarios/Estancamiento/data/input/openMASTER_Data_.xlsx new file mode 100644 index 0000000..158d6ae --- /dev/null +++ b/scenarios/Estancamiento/data/input/openMASTER_Data_.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8be85bbef3219b5bbd6970e59b80db186750f839ee5eae0eb1872e89a1f5f10b +size 1262226 diff --git "a/scenarios/Estancamiento/data/input/openMASTER_Data_Caso_Avance_Tecnol\303\263gico.xlsx" "b/scenarios/Estancamiento/data/input/openMASTER_Data_Caso_Avance_Tecnol\303\263gico.xlsx" new file mode 100644 index 0000000..993bfea --- /dev/null +++ "b/scenarios/Estancamiento/data/input/openMASTER_Data_Caso_Avance_Tecnol\303\263gico.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bf9f6b27e69abbdd2476055329ed00684a8b151b96bef5669c42d6e0cc413bf3 +size 1265882 diff --git a/scenarios/Estancamiento/data/input/openMASTER_Data_Caso_Estancamiento.xlsx b/scenarios/Estancamiento/data/input/openMASTER_Data_Caso_Estancamiento.xlsx new file mode 100644 index 0000000..ad60d9f --- /dev/null +++ b/scenarios/Estancamiento/data/input/openMASTER_Data_Caso_Estancamiento.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a74c8bcf468f645e57055314d7426fc8dae5eef0ac39e1e64c6689986e86ee78 +size 1265746 diff --git "a/scenarios/Estancamiento/data/input/openMASTER_Data_Caso_Mantenimiento_de_Pol\303\255ticas_Descarb.xlsx" "b/scenarios/Estancamiento/data/input/openMASTER_Data_Caso_Mantenimiento_de_Pol\303\255ticas_Descarb.xlsx" new file mode 100644 index 0000000..531b883 --- /dev/null +++ "b/scenarios/Estancamiento/data/input/openMASTER_Data_Caso_Mantenimiento_de_Pol\303\255ticas_Descarb.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4055e80df075ab5f57afe812bc520bc72469c6a0a47bffcc28801e871998496b +size 1265815 diff --git a/scenarios/Estancamiento/data/output/Results.xlsx b/scenarios/Estancamiento/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Estancamiento/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Estancamiento/src/openMASTER/Graphing_Tool/main.py b/scenarios/Estancamiento/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Estancamiento/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Estancamiento/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Estancamiento/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Estancamiento/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Estancamiento/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Estancamiento/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Estancamiento/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Estancamiento/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Estancamiento/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Estancamiento/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Estancamiento/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Estancamiento/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Estancamiento/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Estancamiento/src/openMASTER/GurobiShell.py b/scenarios/Estancamiento/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Estancamiento/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Estancamiento/src/openMASTER/__init__.py b/scenarios/Estancamiento/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Estancamiento/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Estancamiento/src/openMASTER/const.py b/scenarios/Estancamiento/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Estancamiento/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Estancamiento/src/openMASTER/execute_sankey.py b/scenarios/Estancamiento/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Estancamiento/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Estancamiento/src/openMASTER/loader.py b/scenarios/Estancamiento/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Estancamiento/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Estancamiento/src/openMASTER/model.py b/scenarios/Estancamiento/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Estancamiento/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Estancamiento/src/openMASTER/output_data.py b/scenarios/Estancamiento/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Estancamiento/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Estancamiento/src/openMASTER/scenarios.py b/scenarios/Estancamiento/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Estancamiento/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Estancamiento/src/openMASTER/utils.py b/scenarios/Estancamiento/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Estancamiento/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Just_27_06_2024-18_18_37/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_27_06_2024-18_18_37/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_27_06_2024-18_18_37/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_27_06_2024-18_18_37/data/input/Data_Industrial.xlsx b/scenarios/Just_27_06_2024-18_18_37/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_27_06_2024-18_18_37/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_27_06_2024-18_18_37/data/input/Data_Residential.xlsx b/scenarios/Just_27_06_2024-18_18_37/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_27_06_2024-18_18_37/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_27_06_2024-18_18_37/data/input/costs_correl.csv b/scenarios/Just_27_06_2024-18_18_37/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_27_06_2024-18_18_37/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_27_06_2024-18_18_37/data/input/costs_correl_orig.csv b/scenarios/Just_27_06_2024-18_18_37/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_27_06_2024-18_18_37/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_27_06_2024-18_18_37/data/input/covar.xlsx b/scenarios/Just_27_06_2024-18_18_37/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_27_06_2024-18_18_37/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_27_06_2024-18_18_37/data/input/mean.csv b/scenarios/Just_27_06_2024-18_18_37/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_27_06_2024-18_18_37/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_27_06_2024-18_18_37/data/input/openMASTER_Data.xlsx b/scenarios/Just_27_06_2024-18_18_37/data/input/openMASTER_Data.xlsx new file mode 100644 index 0000000..26eab5b --- /dev/null +++ b/scenarios/Just_27_06_2024-18_18_37/data/input/openMASTER_Data.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:204f7be4ab4d61adcc904ba520c53451574daea589923477922e9d1e417ca8e2 +size 1291820 diff --git a/scenarios/Just_27_06_2024-18_18_37/data/output/Results.xlsx b/scenarios/Just_27_06_2024-18_18_37/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_27_06_2024-18_18_37/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/GurobiShell.py b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/__init__.py b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/const.py b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/execute_sankey.py b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/loader.py b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/model.py b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/output_data.py b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/scenarios.py b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/utils.py b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_27_06_2024-18_18_37/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Just_27_06_2024-19_48_04/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_27_06_2024-19_48_04/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_27_06_2024-19_48_04/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_27_06_2024-19_48_04/data/input/Data_Industrial.xlsx b/scenarios/Just_27_06_2024-19_48_04/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_04/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_27_06_2024-19_48_04/data/input/Data_Residential.xlsx b/scenarios/Just_27_06_2024-19_48_04/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_04/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_27_06_2024-19_48_04/data/input/costs_correl.csv b/scenarios/Just_27_06_2024-19_48_04/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_04/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_27_06_2024-19_48_04/data/input/costs_correl_orig.csv b/scenarios/Just_27_06_2024-19_48_04/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_04/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_27_06_2024-19_48_04/data/input/covar.xlsx b/scenarios/Just_27_06_2024-19_48_04/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_04/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_27_06_2024-19_48_04/data/input/mean.csv b/scenarios/Just_27_06_2024-19_48_04/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_04/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_27_06_2024-19_48_04/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_27_06_2024-19_48_04/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..26eab5b --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_04/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:204f7be4ab4d61adcc904ba520c53451574daea589923477922e9d1e417ca8e2 +size 1291820 diff --git a/scenarios/Just_27_06_2024-19_48_04/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_27_06_2024-19_48_04/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_04/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_27_06_2024-19_48_04/data/output/Results.xlsx b/scenarios/Just_27_06_2024-19_48_04/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_04/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git "a/scenarios/Just_27_06_2024-19_48_28/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_27_06_2024-19_48_28/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_27_06_2024-19_48_28/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_27_06_2024-19_48_28/data/input/Data_Industrial.xlsx b/scenarios/Just_27_06_2024-19_48_28/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_28/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_27_06_2024-19_48_28/data/input/Data_Residential.xlsx b/scenarios/Just_27_06_2024-19_48_28/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_28/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_27_06_2024-19_48_28/data/input/costs_correl.csv b/scenarios/Just_27_06_2024-19_48_28/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_28/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_27_06_2024-19_48_28/data/input/costs_correl_orig.csv b/scenarios/Just_27_06_2024-19_48_28/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_28/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_27_06_2024-19_48_28/data/input/covar.xlsx b/scenarios/Just_27_06_2024-19_48_28/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_28/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_27_06_2024-19_48_28/data/input/mean.csv b/scenarios/Just_27_06_2024-19_48_28/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_28/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_27_06_2024-19_48_28/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_27_06_2024-19_48_28/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..26eab5b --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_28/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:204f7be4ab4d61adcc904ba520c53451574daea589923477922e9d1e417ca8e2 +size 1291820 diff --git a/scenarios/Just_27_06_2024-19_48_28/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_27_06_2024-19_48_28/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_28/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_27_06_2024-19_48_28/data/output/Results.xlsx b/scenarios/Just_27_06_2024-19_48_28/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_28/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/GurobiShell.py b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/__init__.py b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/const.py b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/execute_sankey.py b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/loader.py b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/model.py b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/output_data.py b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/scenarios.py b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/utils.py b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_27_06_2024-19_48_28/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Just_v1_01_07_2024-17_07_11/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_01_07_2024-17_07_11/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_01_07_2024-17_07_11/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_01_07_2024-17_07_11/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_07_11/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/data/input/Data_Residential.xlsx b/scenarios/Just_v1_01_07_2024-17_07_11/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_07_11/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/data/input/costs_correl.csv b/scenarios/Just_v1_01_07_2024-17_07_11/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_07_11/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/data/input/costs_correl_orig.csv b/scenarios/Just_v1_01_07_2024-17_07_11/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_07_11/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/data/input/covar.xlsx b/scenarios/Just_v1_01_07_2024-17_07_11/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_07_11/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/data/input/mean.csv b/scenarios/Just_v1_01_07_2024-17_07_11/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_07_11/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_01_07_2024-17_07_11/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..423eaea --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_07_11/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a17c77a432efcc709674a2cc0c0a42cbfbe74fe4222861525e5e101101c0df86 +size 1291826 diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_01_07_2024-17_07_11/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_07_11/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/data/output/Results.xlsx b/scenarios/Just_v1_01_07_2024-17_07_11/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_07_11/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/__init__.py b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/const.py b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/loader.py b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/model.py b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/output_data.py b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/scenarios.py b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/utils.py b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_07_11/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Just_v1_01_07_2024-17_31_08/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_01_07_2024-17_31_08/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_01_07_2024-17_31_08/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_01_07_2024-17_31_08/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_31_08/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/data/input/Data_Residential.xlsx b/scenarios/Just_v1_01_07_2024-17_31_08/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_31_08/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/data/input/costs_correl.csv b/scenarios/Just_v1_01_07_2024-17_31_08/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_31_08/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/data/input/costs_correl_orig.csv b/scenarios/Just_v1_01_07_2024-17_31_08/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_31_08/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/data/input/covar.xlsx b/scenarios/Just_v1_01_07_2024-17_31_08/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_31_08/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/data/input/mean.csv b/scenarios/Just_v1_01_07_2024-17_31_08/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_31_08/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_01_07_2024-17_31_08/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..423eaea --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_31_08/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a17c77a432efcc709674a2cc0c0a42cbfbe74fe4222861525e5e101101c0df86 +size 1291826 diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_01_07_2024-17_31_08/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_31_08/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/data/output/Results.xlsx b/scenarios/Just_v1_01_07_2024-17_31_08/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_31_08/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/__init__.py b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/const.py b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/loader.py b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/model.py b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/output_data.py b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/scenarios.py b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/utils.py b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_31_08/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Just_v1_01_07_2024-17_52_23/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_01_07_2024-17_52_23/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_01_07_2024-17_52_23/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_01_07_2024-17_52_23/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_52_23/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/data/input/Data_Residential.xlsx b/scenarios/Just_v1_01_07_2024-17_52_23/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_52_23/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/data/input/costs_correl.csv b/scenarios/Just_v1_01_07_2024-17_52_23/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_52_23/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/data/input/costs_correl_orig.csv b/scenarios/Just_v1_01_07_2024-17_52_23/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_52_23/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/data/input/covar.xlsx b/scenarios/Just_v1_01_07_2024-17_52_23/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_52_23/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/data/input/mean.csv b/scenarios/Just_v1_01_07_2024-17_52_23/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_52_23/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_01_07_2024-17_52_23/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..423eaea --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_52_23/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a17c77a432efcc709674a2cc0c0a42cbfbe74fe4222861525e5e101101c0df86 +size 1291826 diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_01_07_2024-17_52_23/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_52_23/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/data/output/Results.xlsx b/scenarios/Just_v1_01_07_2024-17_52_23/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_52_23/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/__init__.py b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/const.py b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/loader.py b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/model.py b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/output_data.py b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/scenarios.py b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/utils.py b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-17_52_23/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/Data_Residential.xlsx b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/costs_correl.csv b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/costs_correl_orig.csv b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/covar.xlsx b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/mean.csv b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..423eaea --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a17c77a432efcc709674a2cc0c0a42cbfbe74fe4222861525e5e101101c0df86 +size 1291826 diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/output/Results.xlsx b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/__init__.py b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/const.py b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/loader.py b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/model.py b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/output_data.py b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/scenarios.py b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/utils.py b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_09_45(lacksPM25)/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Just_v1_01_07_2024-18_27_07/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_01_07_2024-18_27_07/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_01_07_2024-18_27_07/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_01_07_2024-18_27_07/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_27_07/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/data/input/Data_Residential.xlsx b/scenarios/Just_v1_01_07_2024-18_27_07/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_27_07/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/data/input/costs_correl.csv b/scenarios/Just_v1_01_07_2024-18_27_07/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_27_07/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/data/input/costs_correl_orig.csv b/scenarios/Just_v1_01_07_2024-18_27_07/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_27_07/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/data/input/covar.xlsx b/scenarios/Just_v1_01_07_2024-18_27_07/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_27_07/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/data/input/mean.csv b/scenarios/Just_v1_01_07_2024-18_27_07/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_27_07/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_01_07_2024-18_27_07/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..423eaea --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_27_07/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a17c77a432efcc709674a2cc0c0a42cbfbe74fe4222861525e5e101101c0df86 +size 1291826 diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_01_07_2024-18_27_07/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_27_07/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/data/output/Results.xlsx b/scenarios/Just_v1_01_07_2024-18_27_07/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_27_07/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/__init__.py b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/const.py b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/loader.py b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/model.py b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/output_data.py b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/scenarios.py b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/utils.py b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_27_07/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Just_v1_01_07_2024-18_42_06/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_01_07_2024-18_42_06/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_01_07_2024-18_42_06/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_01_07_2024-18_42_06/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_42_06/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/data/input/Data_Residential.xlsx b/scenarios/Just_v1_01_07_2024-18_42_06/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_42_06/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/data/input/costs_correl.csv b/scenarios/Just_v1_01_07_2024-18_42_06/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_42_06/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/data/input/costs_correl_orig.csv b/scenarios/Just_v1_01_07_2024-18_42_06/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_42_06/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/data/input/covar.xlsx b/scenarios/Just_v1_01_07_2024-18_42_06/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_42_06/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/data/input/mean.csv b/scenarios/Just_v1_01_07_2024-18_42_06/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_42_06/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_01_07_2024-18_42_06/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..423eaea --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_42_06/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a17c77a432efcc709674a2cc0c0a42cbfbe74fe4222861525e5e101101c0df86 +size 1291826 diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_01_07_2024-18_42_06/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_42_06/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/data/output/Results.xlsx b/scenarios/Just_v1_01_07_2024-18_42_06/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_42_06/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/__init__.py b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/const.py b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/loader.py b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/model.py b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/output_data.py b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/scenarios.py b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/utils.py b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_42_06/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Just_v1_01_07_2024-18_57_18/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_01_07_2024-18_57_18/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_01_07_2024-18_57_18/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_01_07_2024-18_57_18/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_57_18/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/data/input/Data_Residential.xlsx b/scenarios/Just_v1_01_07_2024-18_57_18/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_57_18/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/data/input/costs_correl.csv b/scenarios/Just_v1_01_07_2024-18_57_18/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_57_18/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/data/input/costs_correl_orig.csv b/scenarios/Just_v1_01_07_2024-18_57_18/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_57_18/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/data/input/covar.xlsx b/scenarios/Just_v1_01_07_2024-18_57_18/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_57_18/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/data/input/mean.csv b/scenarios/Just_v1_01_07_2024-18_57_18/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_57_18/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_01_07_2024-18_57_18/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..423eaea --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_57_18/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a17c77a432efcc709674a2cc0c0a42cbfbe74fe4222861525e5e101101c0df86 +size 1291826 diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_01_07_2024-18_57_18/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_57_18/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/data/output/Results.xlsx b/scenarios/Just_v1_01_07_2024-18_57_18/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_57_18/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/__init__.py b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/const.py b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/loader.py b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/model.py b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/output_data.py b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/scenarios.py b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/utils.py b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-18_57_18/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/Data_Residential.xlsx b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/costs_correl.csv b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/costs_correl_orig.csv b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/covar.xlsx b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/mean.csv b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/openMASTER_Data_2050_AllPollutants.xlsx b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/openMASTER_Data_2050_AllPollutants.xlsx new file mode 100644 index 0000000..423eaea --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/openMASTER_Data_2050_AllPollutants.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a17c77a432efcc709674a2cc0c0a42cbfbe74fe4222861525e5e101101c0df86 +size 1291826 diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/output/Results.xlsx b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/__init__.py b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/const.py b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/loader.py b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/model.py b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/output_data.py b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/scenarios.py b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/utils.py b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_01_07_2024-19_10_07(All pollutants activated)/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/data/input/3AECC940 b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/data/input/82776390 b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/82776390 differ diff --git "a/scenarios/Just_v1_01_08_2024-11_52_01/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/data/input/DF6CC940 b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/data/input/Data_Residential.xlsx b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/data/input/costs_correl.csv b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/data/input/costs_correl_orig.csv b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/data/input/covar.xlsx b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/data/input/mean.csv b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/data/input/openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..e00b43f --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2028bff6c3e9addf070e6f26a04adb8cc98fcd43113ebb468b9df979060a1886 +size 1371178 diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b1e1359 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbd712d0db5f2ef18d2e84c68bfb31639e750a788fdfbab894c14d090b0125cd +size 1370254 diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/data/output/Results.xlsx b/scenarios/Just_v1_01_08_2024-11_52_01/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/__init__.py b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/const.py b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/loader.py b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/model.py b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/output_data.py b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/scenarios.py b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/utils.py b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-11_52_01/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/data/input/3AECC940 b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/data/input/82776390 b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/82776390 differ diff --git "a/scenarios/Just_v1_01_08_2024-13_14_32/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/data/input/DF6CC940 b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/data/input/Data_Residential.xlsx b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/data/input/costs_correl.csv b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/data/input/costs_correl_orig.csv b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/data/input/covar.xlsx b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/data/input/mean.csv b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/data/input/openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..52fa91a --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:756efab0d1eaf618504abd7a389c380adfb44c8387c3b7362ab189cd18a74cbe +size 1371243 diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b1e1359 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbd712d0db5f2ef18d2e84c68bfb31639e750a788fdfbab894c14d090b0125cd +size 1370254 diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/data/output/Results.xlsx b/scenarios/Just_v1_01_08_2024-13_14_32/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/__init__.py b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/const.py b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/loader.py b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/model.py b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/output_data.py b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/scenarios.py b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/utils.py b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-13_14_32/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/data/input/3AECC940 b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/data/input/82776390 b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/82776390 differ diff --git "a/scenarios/Just_v1_01_08_2024-16_38_57/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/data/input/DF6CC940 b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/data/input/Data_Residential.xlsx b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/data/input/costs_correl.csv b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/data/input/costs_correl_orig.csv b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/data/input/covar.xlsx b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/data/input/mean.csv b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/data/input/openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..3a15df7 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f1a028f15544e9cc3a57538603541a4229889b21f5de9e8d16d2f2c0205b2178 +size 1371105 diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b1e1359 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbd712d0db5f2ef18d2e84c68bfb31639e750a788fdfbab894c14d090b0125cd +size 1370254 diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/data/output/Results.xlsx b/scenarios/Just_v1_01_08_2024-16_38_57/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/__init__.py b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/const.py b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/loader.py b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/model.py b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/output_data.py b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/scenarios.py b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/utils.py b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-16_38_57/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/data/input/3AECC940 b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/data/input/82776390 b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/82776390 differ diff --git "a/scenarios/Just_v1_01_08_2024-17_04_55/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/data/input/DF6CC940 b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/data/input/Data_Residential.xlsx b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/data/input/costs_correl.csv b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/data/input/costs_correl_orig.csv b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/data/input/covar.xlsx b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/data/input/mean.csv b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/data/input/openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..0104de6 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7252aaf50bb79cf944ec45dbdc8a1e1a535ee36aa673e657a9e4501763f753a6 +size 1371098 diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b1e1359 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbd712d0db5f2ef18d2e84c68bfb31639e750a788fdfbab894c14d090b0125cd +size 1370254 diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/data/output/Results.xlsx b/scenarios/Just_v1_01_08_2024-17_04_55/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/__init__.py b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/const.py b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/loader.py b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/model.py b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/output_data.py b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/scenarios.py b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/utils.py b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-17_04_55/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/data/input/3AECC940 b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/data/input/82776390 b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/82776390 differ diff --git "a/scenarios/Just_v1_01_08_2024-18_14_22/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/data/input/DF6CC940 b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/data/input/Data_Residential.xlsx b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/data/input/costs_correl.csv b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/data/input/costs_correl_orig.csv b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/data/input/covar.xlsx b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/data/input/mean.csv b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/data/input/openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..39250bd --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:16199f8c79930a10383fefe91ee092877804f599e11a7e29d66352ebfbb45f12 +size 1371130 diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b1e1359 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbd712d0db5f2ef18d2e84c68bfb31639e750a788fdfbab894c14d090b0125cd +size 1370254 diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/data/output/Results.xlsx b/scenarios/Just_v1_01_08_2024-18_14_22/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/__init__.py b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/const.py b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/loader.py b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/model.py b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/output_data.py b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/scenarios.py b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/utils.py b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_01_08_2024-18_14_22/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_02_07_2024-09_42_55/data/input/3AECC940 b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/3AECC940 differ diff --git "a/scenarios/Just_v1_02_07_2024-09_42_55/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_02_07_2024-09_42_55/data/input/DF6CC940 b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_02_07_2024-09_42_55/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_02_07_2024-09_42_55/data/input/Data_Residential.xlsx b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_02_07_2024-09_42_55/data/input/costs_correl.csv b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_02_07_2024-09_42_55/data/input/costs_correl_orig.csv b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_02_07_2024-09_42_55/data/input/covar.xlsx b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_02_07_2024-09_42_55/data/input/mean.csv b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_02_07_2024-09_42_55/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..423eaea --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a17c77a432efcc709674a2cc0c0a42cbfbe74fe4222861525e5e101101c0df86 +size 1291826 diff --git a/scenarios/Just_v1_02_07_2024-09_42_55/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..56606a7 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f7b12df6aa020df96f66bcb08cd17910e4632fc771e5e01a1dc08fa2cb0ffeee +size 1292091 diff --git a/scenarios/Just_v1_02_07_2024-09_42_55/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_42_55/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_02_07_2024-09_42_55/data/output/Results.xlsx b/scenarios/Just_v1_02_07_2024-09_42_55/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_42_55/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_02_07_2024-09_43_17/data/input/3AECC940 b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/3AECC940 differ diff --git "a/scenarios/Just_v1_02_07_2024-09_43_17/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_02_07_2024-09_43_17/data/input/DF6CC940 b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_02_07_2024-09_43_17/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_02_07_2024-09_43_17/data/input/Data_Residential.xlsx b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_02_07_2024-09_43_17/data/input/costs_correl.csv b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_02_07_2024-09_43_17/data/input/costs_correl_orig.csv b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_02_07_2024-09_43_17/data/input/covar.xlsx b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_02_07_2024-09_43_17/data/input/mean.csv b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_02_07_2024-09_43_17/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..423eaea --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a17c77a432efcc709674a2cc0c0a42cbfbe74fe4222861525e5e101101c0df86 +size 1291826 diff --git a/scenarios/Just_v1_02_07_2024-09_43_17/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..56606a7 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f7b12df6aa020df96f66bcb08cd17910e4632fc771e5e01a1dc08fa2cb0ffeee +size 1292091 diff --git a/scenarios/Just_v1_02_07_2024-09_43_17/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_17/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_02_07_2024-09_43_17/data/output/Results.xlsx b/scenarios/Just_v1_02_07_2024-09_43_17/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_17/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/3AECC940 b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/3AECC940 differ diff --git "a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/DF6CC940 b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/Data_Residential.xlsx b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/costs_correl.csv b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/costs_correl_orig.csv b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/covar.xlsx b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/mean.csv b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..423eaea --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a17c77a432efcc709674a2cc0c0a42cbfbe74fe4222861525e5e101101c0df86 +size 1291826 diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..56606a7 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f7b12df6aa020df96f66bcb08cd17910e4632fc771e5e01a1dc08fa2cb0ffeee +size 1292091 diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/output/Results.xlsx b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/__init__.py b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/const.py b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/loader.py b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/model.py b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/output_data.py b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/scenarios.py b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/utils.py b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-09_43_35_NewEmissionFactor_Refinery_(ResultsAreWeird)/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_02_07_2024-14_49_44/data/input/3AECC940 b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/3AECC940 differ diff --git "a/scenarios/Just_v1_02_07_2024-14_49_44/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_02_07_2024-14_49_44/data/input/DF6CC940 b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_02_07_2024-14_49_44/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_02_07_2024-14_49_44/data/input/Data_Residential.xlsx b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_02_07_2024-14_49_44/data/input/costs_correl.csv b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_02_07_2024-14_49_44/data/input/costs_correl_orig.csv b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_02_07_2024-14_49_44/data/input/covar.xlsx b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_02_07_2024-14_49_44/data/input/mean.csv b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_02_07_2024-14_49_44/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..423eaea --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a17c77a432efcc709674a2cc0c0a42cbfbe74fe4222861525e5e101101c0df86 +size 1291826 diff --git a/scenarios/Just_v1_02_07_2024-14_49_44/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fd49e3a --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:14e23590279d11040b2c63b26ec33fee3be1727b78de1449564b4ea95da7a226 +size 1292087 diff --git a/scenarios/Just_v1_02_07_2024-14_49_44/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..0de0b29 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f2ed397a7314d0faf609370314199e6d0a03ff4c42d1df4ee440aea5e086ab06 +size 1294717 diff --git a/scenarios/Just_v1_02_07_2024-14_49_44/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_49_44/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_02_07_2024-14_49_44/data/output/Results.xlsx b/scenarios/Just_v1_02_07_2024-14_49_44/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_49_44/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_02_07_2024-14_50_09/data/input/3AECC940 b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/3AECC940 differ diff --git "a/scenarios/Just_v1_02_07_2024-14_50_09/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_02_07_2024-14_50_09/data/input/DF6CC940 b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_02_07_2024-14_50_09/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_02_07_2024-14_50_09/data/input/Data_Residential.xlsx b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_02_07_2024-14_50_09/data/input/costs_correl.csv b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_02_07_2024-14_50_09/data/input/costs_correl_orig.csv b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_02_07_2024-14_50_09/data/input/covar.xlsx b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_02_07_2024-14_50_09/data/input/mean.csv b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_02_07_2024-14_50_09/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..423eaea --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a17c77a432efcc709674a2cc0c0a42cbfbe74fe4222861525e5e101101c0df86 +size 1291826 diff --git a/scenarios/Just_v1_02_07_2024-14_50_09/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..5d7fa1e --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e45d9af148edf22f7c1fc5e703d712092b44d39194ca24919f08483c223aef67 +size 1292101 diff --git a/scenarios/Just_v1_02_07_2024-14_50_09/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..0de0b29 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f2ed397a7314d0faf609370314199e6d0a03ff4c42d1df4ee440aea5e086ab06 +size 1294717 diff --git a/scenarios/Just_v1_02_07_2024-14_50_09/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_50_09/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_02_07_2024-14_50_09/data/output/Results.xlsx b/scenarios/Just_v1_02_07_2024-14_50_09/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_50_09/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/data/input/3AECC940 b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/3AECC940 differ diff --git "a/scenarios/Just_v1_02_07_2024-14_51_06/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/data/input/DF6CC940 b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/data/input/Data_Residential.xlsx b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/data/input/costs_correl.csv b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/data/input/costs_correl_orig.csv b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/data/input/covar.xlsx b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/data/input/mean.csv b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..423eaea --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a17c77a432efcc709674a2cc0c0a42cbfbe74fe4222861525e5e101101c0df86 +size 1291826 diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..5d7fa1e --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e45d9af148edf22f7c1fc5e703d712092b44d39194ca24919f08483c223aef67 +size 1292101 diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..17bae51 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:476cbe4b95d392ac0d8794aee627e6bbaf717183eedf9938da3284b31ecb8c62 +size 1294723 diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/data/output/Results.xlsx b/scenarios/Just_v1_02_07_2024-14_51_06/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/__init__.py b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/const.py b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/loader.py b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/model.py b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/output_data.py b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/scenarios.py b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/utils.py b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_02_07_2024-14_51_06/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/3AECC940 b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/3AECC940 differ diff --git "a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/DF6CC940 b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/Data_Residential.xlsx b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/costs_correl.csv b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/costs_correl_orig.csv b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/covar.xlsx b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/mean.csv b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..423eaea --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a17c77a432efcc709674a2cc0c0a42cbfbe74fe4222861525e5e101101c0df86 +size 1291826 diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..5d7fa1e --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e45d9af148edf22f7c1fc5e703d712092b44d39194ca24919f08483c223aef67 +size 1292101 diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..ea1e59e --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d790b2dc964708f4c2845e13930eb2cbd697e3b1e8b2fe0d5a9ae4262c7741ad +size 1294744 diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/output/Results.xlsx b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/__init__.py b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/const.py b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/loader.py b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/model.py b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/output_data.py b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/scenarios.py b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/utils.py b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-09_58_43(PollutantsActivated_SectorEmissionsCap)/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_03_07_2024-13_25_29/data/input/3AECC940 b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/3AECC940 differ diff --git "a/scenarios/Just_v1_03_07_2024-13_25_29/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_03_07_2024-13_25_29/data/input/DF6CC940 b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_03_07_2024-13_25_29/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_03_07_2024-13_25_29/data/input/Data_Residential.xlsx b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_03_07_2024-13_25_29/data/input/costs_correl.csv b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_03_07_2024-13_25_29/data/input/costs_correl_orig.csv b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_03_07_2024-13_25_29/data/input/covar.xlsx b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_03_07_2024-13_25_29/data/input/mean.csv b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_03_07_2024-13_25_29/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..423eaea --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a17c77a432efcc709674a2cc0c0a42cbfbe74fe4222861525e5e101101c0df86 +size 1291826 diff --git a/scenarios/Just_v1_03_07_2024-13_25_29/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..5d7fa1e --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e45d9af148edf22f7c1fc5e703d712092b44d39194ca24919f08483c223aef67 +size 1292101 diff --git a/scenarios/Just_v1_03_07_2024-13_25_29/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..d06f9b5 --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:65a5588e921162f2a9cfe50953bd2e2c64fce87326c3eb4c0cb0aaa31a25d83e +size 1297222 diff --git a/scenarios/Just_v1_03_07_2024-13_25_29/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-13_25_29/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_03_07_2024-13_25_29/data/output/Results.xlsx b/scenarios/Just_v1_03_07_2024-13_25_29/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_03_07_2024-13_25_29/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/data/input/3AECC940 b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/3AECC940 differ diff --git "a/scenarios/Just_v1_10_07_2024-10_40_49/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/data/input/DF6CC940 b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/data/input/Data_Residential.xlsx b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/data/input/costs_correl.csv b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/data/input/costs_correl_orig.csv b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/data/input/covar.xlsx b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/data/input/mean.csv b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..423eaea --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a17c77a432efcc709674a2cc0c0a42cbfbe74fe4222861525e5e101101c0df86 +size 1291826 diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..d4fed4b --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b351520b7d2ec383865373cb0bbcaecde0a5fae67e40b39a0d7532ac1bd76139 +size 1323035 diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/data/output/Results.xlsx b/scenarios/Just_v1_10_07_2024-10_40_49/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/__init__.py b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/const.py b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/loader.py b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/model.py b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/output_data.py b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/scenarios.py b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/utils.py b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_10_07_2024-10_40_49/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/3AECC940 b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/3AECC940 differ diff --git "a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/DF6CC940 b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/Data_Residential.xlsx b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/costs_correl.csv b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/costs_correl_orig.csv b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/covar.xlsx b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/mean.csv b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..57ee39c --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7cde7a9002f9cfb087069a4832d5ddb326aafd84cfadd7eb49bfb4ab3e070779 +size 1351418 diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/output/Results.xlsx b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/__init__.py b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/const.py b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/loader.py b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/model.py b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/output_data.py b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/scenarios.py b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/utils.py b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_16_07_2024-15_55_43_Trucks/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/data/input/3AECC940 b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/data/input/82776390 b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/82776390 differ diff --git "a/scenarios/Just_v1_17_07_2024-10_47_01/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/data/input/DF6CC940 b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/data/input/Data_Residential.xlsx b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/data/input/costs_correl.csv b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/data/input/costs_correl_orig.csv b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/data/input/covar.xlsx b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/data/input/mean.csv b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..273dd19 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e11b5ef3b1ed3509964bb50715bc9c017d30fe6e23e4d8bbd16f6032c78cf9b6 +size 1369500 diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/data/output/Results.xlsx b/scenarios/Just_v1_17_07_2024-10_47_01/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/__init__.py b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/const.py b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/loader.py b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/model.py b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/output_data.py b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/scenarios.py b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/utils.py b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-10_47_01/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_17_07_2024-12_49_18/data/input/3AECC940 b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_17_07_2024-12_49_18/data/input/82776390 b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/82776390 differ diff --git "a/scenarios/Just_v1_17_07_2024-12_49_18/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_17_07_2024-12_49_18/data/input/Copia de openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/Copia de openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..f00f1d9 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/Copia de openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:39ebab342b67de18d913af4a1015595bf5eb763cb36c6cff1ec218f5b1e25c75 +size 1369444 diff --git a/scenarios/Just_v1_17_07_2024-12_49_18/data/input/DF6CC940 b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_17_07_2024-12_49_18/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_17_07_2024-12_49_18/data/input/Data_Residential.xlsx b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_17_07_2024-12_49_18/data/input/costs_correl.csv b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_17_07_2024-12_49_18/data/input/costs_correl_orig.csv b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_17_07_2024-12_49_18/data/input/covar.xlsx b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_17_07_2024-12_49_18/data/input/mean.csv b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_17_07_2024-12_49_18/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_17_07_2024-12_49_18/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_17_07_2024-12_49_18/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_17_07_2024-12_49_18/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b91abad --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8642a6d9c0563a4b6ec92f82549ea1a19740c9bbea07042b3374bb08d21ecff8 +size 1369444 diff --git a/scenarios/Just_v1_17_07_2024-12_49_18/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_17_07_2024-12_49_18/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-12_49_18/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_17_07_2024-12_49_18/data/output/Results.xlsx b/scenarios/Just_v1_17_07_2024-12_49_18/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-12_49_18/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/data/input/3AECC940 b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/data/input/82776390 b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/82776390 differ diff --git "a/scenarios/Just_v1_17_07_2024-15_58_57/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/data/input/Copia de openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/Copia de openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..f5fc5f2 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/Copia de openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e08d62be1eef5a7e102f36e2496bea6c97aaf57871998078748127a200fa9d56 +size 1369443 diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/data/input/DF6CC940 b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/data/input/Data_Residential.xlsx b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/data/input/costs_correl.csv b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/data/input/costs_correl_orig.csv b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/data/input/covar.xlsx b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/data/input/mean.csv b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b91abad --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8642a6d9c0563a4b6ec92f82549ea1a19740c9bbea07042b3374bb08d21ecff8 +size 1369444 diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/data/output/Results.xlsx b/scenarios/Just_v1_17_07_2024-15_58_57/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/__init__.py b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/const.py b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/loader.py b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/model.py b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/output_data.py b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/scenarios.py b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/utils.py b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_17_07_2024-15_58_57/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/data/input/3AECC940 b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/data/input/82776390 b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/82776390 differ diff --git "a/scenarios/Just_v1_18_07_2024-10_12_35/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/data/input/DF6CC940 b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/data/input/Data_Residential.xlsx b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/data/input/costs_correl.csv b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/data/input/costs_correl_orig.csv b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/data/input/covar.xlsx b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/data/input/mean.csv b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/data/input/openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..41691cd --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e049f4003edb0c2b391ddfb62fad9ebd3cbd1875454b722a0330b3c1a590e4a5 +size 1370839 diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b91abad --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8642a6d9c0563a4b6ec92f82549ea1a19740c9bbea07042b3374bb08d21ecff8 +size 1369444 diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/data/output/Results.xlsx b/scenarios/Just_v1_18_07_2024-10_12_35/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/__init__.py b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/const.py b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/loader.py b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/model.py b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/output_data.py b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/scenarios.py b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/utils.py b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-10_12_35/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/data/input/3AECC940 b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/data/input/82776390 b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/82776390 differ diff --git "a/scenarios/Just_v1_18_07_2024-14_54_36/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/data/input/DF6CC940 b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/data/input/Data_Residential.xlsx b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/data/input/costs_correl.csv b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/data/input/costs_correl_orig.csv b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/data/input/covar.xlsx b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/data/input/mean.csv b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/data/input/openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..d065655 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5cc5044f9adc1b493173a365973fc25d8fc7fa5ed58eb59f8b8169a8cf9dd1ca +size 1361604 diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b1e1359 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbd712d0db5f2ef18d2e84c68bfb31639e750a788fdfbab894c14d090b0125cd +size 1370254 diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/data/output/Results.xlsx b/scenarios/Just_v1_18_07_2024-14_54_36/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/__init__.py b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/const.py b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/loader.py b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/model.py b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/output_data.py b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/scenarios.py b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/utils.py b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_18_07_2024-14_54_36/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/3AECC940 b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/82776390 b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/82776390 differ diff --git "a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/DF6CC940 b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/Data_Residential.xlsx b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/costs_correl.csv b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/costs_correl_orig.csv b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/covar.xlsx b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/mean.csv b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..3c9664b --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:74d9da4d5a486048ab3515583b4b9d137603ba90bf7b7a8f1d769aa48ef40d7e +size 1366964 diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b1e1359 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbd712d0db5f2ef18d2e84c68bfb31639e750a788fdfbab894c14d090b0125cd +size 1370254 diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/output/Results.xlsx b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/__init__.py b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/const.py b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/loader.py b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/model.py b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/output_data.py b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/scenarios.py b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/utils.py b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-10_53_46_STPathway_v1/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/3AECC940 b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/82776390 b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/82776390 differ diff --git "a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/DF6CC940 b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/Data_Residential.xlsx b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/costs_correl.csv b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/costs_correl_orig.csv b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/covar.xlsx b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/mean.csv b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..5ff8aff --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:174e9b034576caa22b00eefaf62b101b39737d40a016307709cdc17a1257caa4 +size 1367455 diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b1e1359 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbd712d0db5f2ef18d2e84c68bfb31639e750a788fdfbab894c14d090b0125cd +size 1370254 diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/output/Results.xlsx b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/__init__.py b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/const.py b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/loader.py b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/model.py b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/output_data.py b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/scenarios.py b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/utils.py b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-11_59_20_STPathway_v1.0.1/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/3AECC940 b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/82776390 b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/82776390 differ diff --git "a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/DF6CC940 b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/Data_Residential.xlsx b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/costs_correl.csv b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/costs_correl_orig.csv b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/covar.xlsx b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/mean.csv b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..cbefef5 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0f3b3a0eda1057f18315c948a5b91c36755bb031c6c7e6fc675278b482a279fa +size 1367447 diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b1e1359 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbd712d0db5f2ef18d2e84c68bfb31639e750a788fdfbab894c14d090b0125cd +size 1370254 diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/output/Results.xlsx b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/__init__.py b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/const.py b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/loader.py b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/model.py b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/output_data.py b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/scenarios.py b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/utils.py b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_19_07_2024-13_24_56_STPathway_v1.0.2/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/3AECC940 b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/82776390 b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/82776390 differ diff --git "a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/DF6CC940 b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/Data_Residential.xlsx b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/costs_correl.csv b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/costs_correl_orig.csv b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/covar.xlsx b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/mean.csv b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..d994269 --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:41b64705c3c520cc242a7309c9fa507c7f0db7ef968afc1959934a6f002e68f9 +size 1371133 diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b1e1359 --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbd712d0db5f2ef18d2e84c68bfb31639e750a788fdfbab894c14d090b0125cd +size 1370254 diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/output/Results.xlsx b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/__init__.py b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/const.py b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/loader.py b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/model.py b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/output_data.py b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/scenarios.py b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/utils.py b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_19_09_2024-13_10_27_STPathway_v1.0.3/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/3AECC940 b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/82776390 b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/82776390 differ diff --git "a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/DF6CC940 b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/Data_Residential.xlsx b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/costs_correl.csv b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/costs_correl_orig.csv b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/covar.xlsx b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/mean.csv b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..44d4c12 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:58e02890cd2b1f0fe3487912fb5de81631f1f16207d4980bdc0226ac6320c3d8 +size 1370397 diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b1e1359 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbd712d0db5f2ef18d2e84c68bfb31639e750a788fdfbab894c14d090b0125cd +size 1370254 diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/output/Results.xlsx b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/__init__.py b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/const.py b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/loader.py b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/model.py b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/output_data.py b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/scenarios.py b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/utils.py b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-11_47_51_(COHERENTRES/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/data/input/3AECC940 b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/data/input/82776390 b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/82776390 differ diff --git "a/scenarios/Just_v1_23_07_2024-12_31_43/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/data/input/DF6CC940 b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/data/input/Data_Residential.xlsx b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/data/input/costs_correl.csv b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/data/input/costs_correl_orig.csv b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/data/input/covar.xlsx b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/data/input/mean.csv b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/data/input/openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..0258810 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ba2332124bc1b02e9a4e7aa63b7fae122945de7f708e7ac0a9c65ad870dd762c +size 1370771 diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b1e1359 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbd712d0db5f2ef18d2e84c68bfb31639e750a788fdfbab894c14d090b0125cd +size 1370254 diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/data/output/Results.xlsx b/scenarios/Just_v1_23_07_2024-12_31_43/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/__init__.py b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/const.py b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/loader.py b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/model.py b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/output_data.py b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/scenarios.py b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/utils.py b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-12_31_43/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/data/input/3AECC940 b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/data/input/82776390 b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/82776390 differ diff --git "a/scenarios/Just_v1_23_07_2024-16_55_33/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/data/input/DF6CC940 b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/data/input/Data_Residential.xlsx b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/data/input/costs_correl.csv b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/data/input/costs_correl_orig.csv b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/data/input/covar.xlsx b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/data/input/mean.csv b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/data/input/openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..2307c93 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:14c5a48d5eab809778a23e436b5afd7e5792bc9e514f2018b41217b0b10f6e48 +size 1371025 diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b1e1359 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbd712d0db5f2ef18d2e84c68bfb31639e750a788fdfbab894c14d090b0125cd +size 1370254 diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/data/output/Results.xlsx b/scenarios/Just_v1_23_07_2024-16_55_33/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/__init__.py b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/const.py b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/loader.py b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/model.py b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/output_data.py b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/scenarios.py b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/utils.py b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_23_07_2024-16_55_33/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/data/input/3AECC940 b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/data/input/82776390 b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/82776390 differ diff --git "a/scenarios/Just_v1_26_07_2024-11_08_42/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/data/input/DF6CC940 b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/data/input/Data_Residential.xlsx b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/data/input/costs_correl.csv b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/data/input/costs_correl_orig.csv b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/data/input/covar.xlsx b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/data/input/mean.csv b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/data/input/openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..dbb98f4 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d1ecb9700e8e82627724fbe88c5851b541294032f0dd636c6f087f2f07324d39 +size 1371108 diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b1e1359 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbd712d0db5f2ef18d2e84c68bfb31639e750a788fdfbab894c14d090b0125cd +size 1370254 diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/data/output/Results.xlsx b/scenarios/Just_v1_26_07_2024-11_08_42/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/__init__.py b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/const.py b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/loader.py b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/model.py b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/output_data.py b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/scenarios.py b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/utils.py b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-11_08_42/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/data/input/3AECC940 b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/data/input/82776390 b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/82776390 differ diff --git "a/scenarios/Just_v1_26_07_2024-12_57_59/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/data/input/DF6CC940 b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/data/input/Data_Residential.xlsx b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/data/input/costs_correl.csv b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/data/input/costs_correl_orig.csv b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/data/input/covar.xlsx b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/data/input/mean.csv b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/data/input/openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..67f9f6d --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dd48bfd8ec3a8ad1784d73601e2eb07d5aceb96556a67697949cf8f63c284987 +size 1371194 diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b1e1359 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbd712d0db5f2ef18d2e84c68bfb31639e750a788fdfbab894c14d090b0125cd +size 1370254 diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/data/output/Results.xlsx b/scenarios/Just_v1_26_07_2024-12_57_59/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/__init__.py b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/const.py b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/loader.py b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/model.py b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/output_data.py b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/scenarios.py b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/utils.py b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_26_07_2024-12_57_59/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git "a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/Data_Residential.xlsx b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/costs_correl.csv b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/costs_correl_orig.csv b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/covar.xlsx b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/mean.csv b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..0f59d6e --- /dev/null +++ b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eb6a66c10d47acdaad36fe91f58e4f1d80ac7a8c93dcb4202cc5d49c869a831a +size 1291878 diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/output/Results.xlsx b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/__init__.py b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/const.py b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/loader.py b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/model.py b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/output_data.py b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/scenarios.py b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/utils.py b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_27_06_2024-20_06_30(PollutantsActivated_WG)/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/data/input/3AECC940 b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/data/input/82776390 b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/82776390 differ diff --git "a/scenarios/Just_v1_31_07_2024-16_29_17/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/data/input/DF6CC940 b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/data/input/Data_Residential.xlsx b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/data/input/costs_correl.csv b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/data/input/costs_correl_orig.csv b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/data/input/covar.xlsx b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/data/input/mean.csv b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/data/input/openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..f8d7457 --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a607376720d9b26feb97924f8bf49d18e4b02e940184e44af221f538de493bd6 +size 1371190 diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b1e1359 --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbd712d0db5f2ef18d2e84c68bfb31639e750a788fdfbab894c14d090b0125cd +size 1370254 diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/data/output/Results.xlsx b/scenarios/Just_v1_31_07_2024-16_29_17/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/__init__.py b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/const.py b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/loader.py b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/model.py b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/output_data.py b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/scenarios.py b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/utils.py b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_31_07_2024-16_29_17/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/3AECC940 b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/3AECC940 differ diff --git "a/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/DF6CC940 b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/Data_Residential.xlsx b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/costs_correl.csv b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/costs_correl_orig.csv b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/covar.xlsx b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/mean.csv b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..423eaea --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a17c77a432efcc709674a2cc0c0a42cbfbe74fe4222861525e5e101101c0df86 +size 1291826 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..d06f9b5 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:65a5588e921162f2a9cfe50953bd2e2c64fce87326c3eb4c0cb0aaa31a25d83e +size 1297222 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/output/Results.xlsx b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/__init__.py b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/const.py b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/loader.py b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/model.py b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/output_data.py b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/scenarios.py b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/utils.py b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/3AECC940 b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/3AECC940 differ diff --git "a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/DF6CC940 b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/Data_Residential.xlsx b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/costs_correl.csv b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/costs_correl_orig.csv b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/covar.xlsx b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/mean.csv b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..423eaea --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a17c77a432efcc709674a2cc0c0a42cbfbe74fe4222861525e5e101101c0df86 +size 1291826 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..1e7d236 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:33140a00be8b02386eb9d65f651f4a4b0f8fed88c62a2c6f223270cb12062006 +size 1297557 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/output/Results.xlsx b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/__init__.py b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/const.py b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/loader.py b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/model.py b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/output_data.py b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/scenarios.py b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/utils.py b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_AllPollutantsActivated_STResModified_SectorCapModified_BESTONE/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_STPathway_v1.0.2/data/input/3AECC940 b/scenarios/Just_v1_STPathway_v1.0.2/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_STPathway_v1.0.2/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_STPathway_v1.0.2/data/input/82776390 b/scenarios/Just_v1_STPathway_v1.0.2/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_STPathway_v1.0.2/data/input/82776390 differ diff --git "a/scenarios/Just_v1_STPathway_v1.0.2/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_STPathway_v1.0.2/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_STPathway_v1.0.2/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_STPathway_v1.0.2/data/input/DF6CC940 b/scenarios/Just_v1_STPathway_v1.0.2/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_STPathway_v1.0.2/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_STPathway_v1.0.2/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_STPathway_v1.0.2/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_STPathway_v1.0.2/data/input/Data_Residential.xlsx b/scenarios/Just_v1_STPathway_v1.0.2/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_STPathway_v1.0.2/data/input/costs_correl.csv b/scenarios/Just_v1_STPathway_v1.0.2/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_STPathway_v1.0.2/data/input/costs_correl_orig.csv b/scenarios/Just_v1_STPathway_v1.0.2/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_STPathway_v1.0.2/data/input/covar.xlsx b/scenarios/Just_v1_STPathway_v1.0.2/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_STPathway_v1.0.2/data/input/mean.csv b/scenarios/Just_v1_STPathway_v1.0.2/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_STPathway_v1.0.2/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_STPathway_v1.0.2/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_STPathway_v1.0.2/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_STPathway_v1.0.2/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..1789abb --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:50eb3e267d152fb1667e00b8053ef9cccfed45815a34d5532cab39a28bce1e70 +size 1363388 diff --git a/scenarios/Just_v1_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b1e1359 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbd712d0db5f2ef18d2e84c68bfb31639e750a788fdfbab894c14d090b0125cd +size 1370254 diff --git a/scenarios/Just_v1_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_STPathway_v1.0.2/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_STPathway_v1.0.2/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_STPathway_v1.0.2/data/output/Results.xlsx b/scenarios/Just_v1_STPathway_v1.0.2/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/__init__.py b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/const.py b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/loader.py b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/model.py b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/output_data.py b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/scenarios.py b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/utils.py b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.2/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_STPathway_v1.0.3/data/input/3AECC940 b/scenarios/Just_v1_STPathway_v1.0.3/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_STPathway_v1.0.3/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_STPathway_v1.0.3/data/input/82776390 b/scenarios/Just_v1_STPathway_v1.0.3/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_STPathway_v1.0.3/data/input/82776390 differ diff --git "a/scenarios/Just_v1_STPathway_v1.0.3/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_STPathway_v1.0.3/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_STPathway_v1.0.3/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_STPathway_v1.0.3/data/input/DF6CC940 b/scenarios/Just_v1_STPathway_v1.0.3/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_STPathway_v1.0.3/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_STPathway_v1.0.3/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_STPathway_v1.0.3/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_STPathway_v1.0.3/data/input/Data_Residential.xlsx b/scenarios/Just_v1_STPathway_v1.0.3/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_STPathway_v1.0.3/data/input/costs_correl.csv b/scenarios/Just_v1_STPathway_v1.0.3/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_STPathway_v1.0.3/data/input/costs_correl_orig.csv b/scenarios/Just_v1_STPathway_v1.0.3/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_STPathway_v1.0.3/data/input/covar.xlsx b/scenarios/Just_v1_STPathway_v1.0.3/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_STPathway_v1.0.3/data/input/mean.csv b/scenarios/Just_v1_STPathway_v1.0.3/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_STPathway_v1.0.3/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_STPathway_v1.0.3/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_STPathway_v1.0.3/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_STPathway_v1.0.3/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..d65faaf --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:32b07d47ceb97cc446c3c3aa15faef196072b47794f887899c9a0acf73669364 +size 1370782 diff --git a/scenarios/Just_v1_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b1e1359 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbd712d0db5f2ef18d2e84c68bfb31639e750a788fdfbab894c14d090b0125cd +size 1370254 diff --git a/scenarios/Just_v1_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_STPathway_v1.0.3/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_STPathway_v1.0.3/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_STPathway_v1.0.3/data/output/Results.xlsx b/scenarios/Just_v1_STPathway_v1.0.3/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/__init__.py b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/const.py b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/loader.py b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/model.py b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/output_data.py b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/scenarios.py b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/utils.py b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.3/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_STPathway_v1.0.4/data/input/3AECC940 b/scenarios/Just_v1_STPathway_v1.0.4/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_STPathway_v1.0.4/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_STPathway_v1.0.4/data/input/82776390 b/scenarios/Just_v1_STPathway_v1.0.4/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_STPathway_v1.0.4/data/input/82776390 differ diff --git "a/scenarios/Just_v1_STPathway_v1.0.4/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_STPathway_v1.0.4/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_STPathway_v1.0.4/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_STPathway_v1.0.4/data/input/DF6CC940 b/scenarios/Just_v1_STPathway_v1.0.4/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_STPathway_v1.0.4/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_STPathway_v1.0.4/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_STPathway_v1.0.4/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_STPathway_v1.0.4/data/input/Data_Residential.xlsx b/scenarios/Just_v1_STPathway_v1.0.4/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_STPathway_v1.0.4/data/input/costs_correl.csv b/scenarios/Just_v1_STPathway_v1.0.4/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_STPathway_v1.0.4/data/input/costs_correl_orig.csv b/scenarios/Just_v1_STPathway_v1.0.4/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_STPathway_v1.0.4/data/input/covar.xlsx b/scenarios/Just_v1_STPathway_v1.0.4/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_STPathway_v1.0.4/data/input/mean.csv b/scenarios/Just_v1_STPathway_v1.0.4/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_STPathway_v1.0.4/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_STPathway_v1.0.4/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_STPathway_v1.0.4/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_STPathway_v1.0.4/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_STPathway_v1.0.4/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_STPathway_v1.0.4/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_STPathway_v1.0.4/data/input/openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_STPathway_v1.0.4/data/input/openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..b030d31 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/data/input/openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2f0324ae33f1448329cbfe76d4a97c2d872fb2fddba8075135ae695ed13c91d3 +size 1370955 diff --git a/scenarios/Just_v1_STPathway_v1.0.4/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_STPathway_v1.0.4/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b1e1359 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbd712d0db5f2ef18d2e84c68bfb31639e750a788fdfbab894c14d090b0125cd +size 1370254 diff --git a/scenarios/Just_v1_STPathway_v1.0.4/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_STPathway_v1.0.4/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_STPathway_v1.0.4/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_STPathway_v1.0.4/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_STPathway_v1.0.4/data/output/Results.xlsx b/scenarios/Just_v1_STPathway_v1.0.4/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/__init__.py b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/const.py b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/loader.py b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/model.py b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/output_data.py b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/scenarios.py b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/utils.py b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.4/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_STPathway_v1.0.5/data/input/3AECC940 b/scenarios/Just_v1_STPathway_v1.0.5/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_STPathway_v1.0.5/data/input/3AECC940 differ diff --git a/scenarios/Just_v1_STPathway_v1.0.5/data/input/82776390 b/scenarios/Just_v1_STPathway_v1.0.5/data/input/82776390 new file mode 100644 index 0000000..01d7a28 Binary files /dev/null and b/scenarios/Just_v1_STPathway_v1.0.5/data/input/82776390 differ diff --git "a/scenarios/Just_v1_STPathway_v1.0.5/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_STPathway_v1.0.5/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_STPathway_v1.0.5/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_STPathway_v1.0.5/data/input/DF6CC940 b/scenarios/Just_v1_STPathway_v1.0.5/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_STPathway_v1.0.5/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_STPathway_v1.0.5/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_STPathway_v1.0.5/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_STPathway_v1.0.5/data/input/Data_Residential.xlsx b/scenarios/Just_v1_STPathway_v1.0.5/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_STPathway_v1.0.5/data/input/costs_correl.csv b/scenarios/Just_v1_STPathway_v1.0.5/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_STPathway_v1.0.5/data/input/costs_correl_orig.csv b/scenarios/Just_v1_STPathway_v1.0.5/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_STPathway_v1.0.5/data/input/covar.xlsx b/scenarios/Just_v1_STPathway_v1.0.5/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_STPathway_v1.0.5/data/input/mean.csv b/scenarios/Just_v1_STPathway_v1.0.5/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_STPathway_v1.0.5/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_STPathway_v1.0.5/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_STPathway_v1.0.5/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_STPathway_v1.0.5/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_STPathway_v1.0.5/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_STPathway_v1.0.5/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..6a9a273 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c31c04c31ba63a8dcd14fb3da22d0a6952a38ad2f3be12d39d8d591025d1e9 +size 1349327 diff --git a/scenarios/Just_v1_STPathway_v1.0.5/data/input/openMASTER_Data_2050_v1_STPathway.xlsx b/scenarios/Just_v1_STPathway_v1.0.5/data/input/openMASTER_Data_2050_v1_STPathway.xlsx new file mode 100644 index 0000000..8f8c7e4 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/data/input/openMASTER_Data_2050_v1_STPathway.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cdff59ba60ef895f6a66c45413c7bb81baed2343b7a77359f1f345cb3024e99d +size 1371061 diff --git a/scenarios/Just_v1_STPathway_v1.0.5/data/input/openMASTER_Data_2050_v1_Truck.xlsx b/scenarios/Just_v1_STPathway_v1.0.5/data/input/openMASTER_Data_2050_v1_Truck.xlsx new file mode 100644 index 0000000..b1e1359 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/data/input/openMASTER_Data_2050_v1_Truck.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbd712d0db5f2ef18d2e84c68bfb31639e750a788fdfbab894c14d090b0125cd +size 1370254 diff --git a/scenarios/Just_v1_STPathway_v1.0.5/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx b/scenarios/Just_v1_STPathway_v1.0.5/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx new file mode 100644 index 0000000..67d10ed --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/data/input/openMASTER_Data_2050_v1_Truck_PathwayCE.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a22d5d1603e8df97095596da8388a6211a74b7548a8d336dfee7bb831085b6fe +size 1351975 diff --git a/scenarios/Just_v1_STPathway_v1.0.5/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_STPathway_v1.0.5/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_STPathway_v1.0.5/data/output/Results.xlsx b/scenarios/Just_v1_STPathway_v1.0.5/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/__init__.py b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/const.py b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/loader.py b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/model.py b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/output_data.py b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/scenarios.py b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/utils.py b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_STPathway_v1.0.5/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_pESLoadModified/data/input/3AECC940 b/scenarios/Just_v1_pESLoadModified/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_pESLoadModified/data/input/3AECC940 differ diff --git "a/scenarios/Just_v1_pESLoadModified/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_pESLoadModified/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_pESLoadModified/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_pESLoadModified/data/input/DF6CC940 b/scenarios/Just_v1_pESLoadModified/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_pESLoadModified/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_pESLoadModified/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_pESLoadModified/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_pESLoadModified/data/input/Data_Residential.xlsx b/scenarios/Just_v1_pESLoadModified/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_pESLoadModified/data/input/costs_correl.csv b/scenarios/Just_v1_pESLoadModified/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_pESLoadModified/data/input/costs_correl_orig.csv b/scenarios/Just_v1_pESLoadModified/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_pESLoadModified/data/input/covar.xlsx b/scenarios/Just_v1_pESLoadModified/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_pESLoadModified/data/input/mean.csv b/scenarios/Just_v1_pESLoadModified/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_pESLoadModified/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_pESLoadModified/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..423eaea --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a17c77a432efcc709674a2cc0c0a42cbfbe74fe4222861525e5e101101c0df86 +size 1291826 diff --git a/scenarios/Just_v1_pESLoadModified/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_pESLoadModified/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_pESLoadModified/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_pESLoadModified/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..d4fed4b --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b351520b7d2ec383865373cb0bbcaecde0a5fae67e40b39a0d7532ac1bd76139 +size 1323035 diff --git a/scenarios/Just_v1_pESLoadModified/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_pESLoadModified/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_pESLoadModified/data/output/Results.xlsx b/scenarios/Just_v1_pESLoadModified/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_pESLoadModified/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_pESLoadModified/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_pESLoadModified/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_pESLoadModified/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_pESLoadModified/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_pESLoadModified/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_pESLoadModified/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_pESLoadModified/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_pESLoadModified/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_pESLoadModified/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_pESLoadModified/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_pESLoadModified/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_pESLoadModified/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_pESLoadModified/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_pESLoadModified/src/openMASTER/__init__.py b/scenarios/Just_v1_pESLoadModified/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_pESLoadModified/src/openMASTER/const.py b/scenarios/Just_v1_pESLoadModified/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_pESLoadModified/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_pESLoadModified/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_pESLoadModified/src/openMASTER/loader.py b/scenarios/Just_v1_pESLoadModified/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_pESLoadModified/src/openMASTER/model.py b/scenarios/Just_v1_pESLoadModified/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_pESLoadModified/src/openMASTER/output_data.py b/scenarios/Just_v1_pESLoadModified/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_pESLoadModified/src/openMASTER/scenarios.py b/scenarios/Just_v1_pESLoadModified/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_pESLoadModified/src/openMASTER/utils.py b/scenarios/Just_v1_pESLoadModified/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/3AECC940 b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/3AECC940 new file mode 100644 index 0000000..dd56308 Binary files /dev/null and b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/3AECC940 differ diff --git "a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" "b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" new file mode 100644 index 0000000..387d5e6 --- /dev/null +++ "b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/Balance Energetico Espa\303\261a definitivo 2022.xlsx" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ec62af4fb277dc84b28fcc4415bd35b5394ea719fd1a0b1273b175edee84ed +size 2095844 diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/DF6CC940 b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/DF6CC940 new file mode 100644 index 0000000..b3db8c2 Binary files /dev/null and b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/DF6CC940 differ diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/Data_Industrial.xlsx b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..d8bc9b5 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a18ed95a8e6cb48e712faddd0c90bbbc2811109519b9e2f04d355bff56193b1d +size 186936 diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/Data_Residential.xlsx b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/costs_correl.csv b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/costs_correl.csv new file mode 100644 index 0000000..a1c9955 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c3c9015952dd7b611415db97293c7fecac05eb223610de247a9de89e8dfe03f +size 4506 diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/costs_correl_orig.csv b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/costs_correl_orig.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/costs_correl_orig.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/covar.xlsx b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/covar.xlsx new file mode 100644 index 0000000..67b924c --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af7ebeaecc5b480cd39bcb1d1421f5b8cf3112e6490f919bbf2fc16979ad0dfa +size 152367 diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/mean.csv b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/mean.csv new file mode 100644 index 0000000..a18935e --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da92096cc0e325838052863674aa2846473de84611bef435d9612e5104f42772 +size 1054 diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/openMASTER_Data_2050.xlsx b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/openMASTER_Data_2050.xlsx new file mode 100644 index 0000000..1dd1330 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/openMASTER_Data_2050.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ed42aca8107bc783973b18d59abbc91021931e29ce5d5b293c34aba9b4e7c5b +size 1292590 diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx new file mode 100644 index 0000000..fbe3175 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/openMASTER_Data_2050_AllPollutants_WG.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b53758a062126f6e29c5a26a76906e91e9458ea18e26dbeb6c4effc27620e9b +size 1292105 diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/openMASTER_Data_2050_v1.xlsx b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/openMASTER_Data_2050_v1.xlsx new file mode 100644 index 0000000..93a76a3 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/openMASTER_Data_2050_v1.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:69a7af0287b74eb24c4f033a4838ccef7d372ff0453358195db04ca24a392e4b +size 1329995 diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/openMASTER_Data_2070.xlsx b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/openMASTER_Data_2070.xlsx new file mode 100644 index 0000000..9c8fb81 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/input/openMASTER_Data_2070.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4e05b18fe024e90dba4ec8e72e885f8e8fda18404b0b4639054c04043b510871 +size 1293666 diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/output/Results.xlsx b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/Graphing_Tool/main.py b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/Graphing_Tool/sankey.py b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/GurobiShell.py b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/__init__.py b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/const.py b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/execute_sankey.py b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/loader.py b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/loader.py new file mode 100644 index 0000000..3c665df --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values[:,0] + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/model.py b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/model.py new file mode 100644 index 0000000..a93979e --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/model.py @@ -0,0 +1,1867 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) * 1e-2 + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + 'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + 'EQ_InvCostCE', + 'EQ_InvCostST', + 'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + #'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + #'EQ_EmiCO2Budget', + #'EQ_EmiCO2CapTra', + #'EQ_EmiCO2CapEle', + #'EQ_EmiCO2CapIndTE', + #'EQ_EmiCO2CapIndPro', + #'EQ_EmiCO2CapOth', + #'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/output_data.py b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/scenarios.py b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/utils.py b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios/Just_v1_pESLoadModified_PEpricesAdjusted_pCEAF_WG/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios_orig/Correl_-0_5/data/input/Data_Industrial.xlsx b/scenarios_orig/Correl_-0_5/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..6c16429 --- /dev/null +++ b/scenarios_orig/Correl_-0_5/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:453ebf662c132fc75ff1e45f0bab9847e7da232a1ac4271c9217274162df8d8d +size 152531 diff --git a/scenarios_orig/Correl_-0_5/data/input/Data_Residential.xlsx b/scenarios_orig/Correl_-0_5/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios_orig/Correl_-0_5/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios_orig/Correl_-0_5/data/input/costs_correl.csv b/scenarios_orig/Correl_-0_5/data/input/costs_correl.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios_orig/Correl_-0_5/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios_orig/Correl_-0_5/data/input/covar.xlsx b/scenarios_orig/Correl_-0_5/data/input/covar.xlsx new file mode 100644 index 0000000..d27152b --- /dev/null +++ b/scenarios_orig/Correl_-0_5/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e0f334bf64291d2524d022361ffcea73cbe6e6f85b5ebf7e9d05b93586d5e6e7 +size 78940 diff --git a/scenarios_orig/Correl_-0_5/data/input/mean.csv b/scenarios_orig/Correl_-0_5/data/input/mean.csv new file mode 100644 index 0000000..2fff9e5 --- /dev/null +++ b/scenarios_orig/Correl_-0_5/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a91b8faab482cbdc4c145ae040244c3ffae0448ccb16ab87568d269b2dd1f0e3 +size 938 diff --git a/scenarios_orig/Correl_-0_5/data/input/openMASTER_Data.xlsm b/scenarios_orig/Correl_-0_5/data/input/openMASTER_Data.xlsm new file mode 100644 index 0000000..318866c --- /dev/null +++ b/scenarios_orig/Correl_-0_5/data/input/openMASTER_Data.xlsm @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6dce092c8e1d2a5d6fdfa66a870dc530d57af874cc7c6d2283d692d40e15847d +size 3075435 diff --git a/scenarios_orig/Correl_-0_5/data/input/openMASTER_Data.xlsx b/scenarios_orig/Correl_-0_5/data/input/openMASTER_Data.xlsx new file mode 100644 index 0000000..910c5a0 --- /dev/null +++ b/scenarios_orig/Correl_-0_5/data/input/openMASTER_Data.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7ef763d71a16579107012d88bf8b8c22637221276b1b47d98af1383a8bf2d876 +size 1236941 diff --git a/scenarios_orig/Correl_-0_5/data/output/Results.xlsx b/scenarios_orig/Correl_-0_5/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios_orig/Correl_-0_5/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios_orig/Correl_-0_5/src/openMASTER/Graphing_Tool/main.py b/scenarios_orig/Correl_-0_5/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios_orig/Correl_-0_5/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios_orig/Correl_-0_5/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios_orig/Correl_-0_5/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios_orig/Correl_-0_5/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios_orig/Correl_-0_5/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios_orig/Correl_-0_5/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios_orig/Correl_-0_5/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios_orig/Correl_-0_5/src/openMASTER/Graphing_Tool/sankey.py b/scenarios_orig/Correl_-0_5/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios_orig/Correl_-0_5/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios_orig/Correl_-0_5/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios_orig/Correl_-0_5/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios_orig/Correl_-0_5/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios_orig/Correl_-0_5/src/openMASTER/GurobiShell.py b/scenarios_orig/Correl_-0_5/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios_orig/Correl_-0_5/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios_orig/Correl_-0_5/src/openMASTER/__init__.py b/scenarios_orig/Correl_-0_5/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios_orig/Correl_-0_5/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios_orig/Correl_-0_5/src/openMASTER/const.py b/scenarios_orig/Correl_-0_5/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios_orig/Correl_-0_5/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios_orig/Correl_-0_5/src/openMASTER/execute_sankey.py b/scenarios_orig/Correl_-0_5/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios_orig/Correl_-0_5/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios_orig/Correl_-0_5/src/openMASTER/loader.py b/scenarios_orig/Correl_-0_5/src/openMASTER/loader.py new file mode 100644 index 0000000..70de7be --- /dev/null +++ b/scenarios_orig/Correl_-0_5/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios_orig/Correl_-0_5/src/openMASTER/model.py b/scenarios_orig/Correl_-0_5/src/openMASTER/model.py new file mode 100644 index 0000000..dfe5226 --- /dev/null +++ b/scenarios_orig/Correl_-0_5/src/openMASTER/model.py @@ -0,0 +1,1835 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.f,m.sUnc, within=Reals, doc = '') + m.pAlpha_do = Param(m.f,m.sUnc, within=Reals, doc = '') + m.pRest = Param(m.f,m.sUnc, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[f,sPE] for f in m.f1) + sum(m.pRest[f,sPE] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[f,sCE] for f in m.f1) + sum(m.pRest[f,sCE] for f in m.fr)) for sCE in m.sCE ) + )) + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[f1,sPE] - m.pAlpha_do[f1,sPE]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[f1,sCE] - m.pAlpha_do[f1,sCE]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-2* m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + 'EQ_TotalCost_Unc', + #'EQ_UncCost', + 'EQ_UncCost_Cher', + 'EQ_UncCost_Cher2', + 'EQ_InvCostCE_Unc', + 'EQ_OpCost_Unc', + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + #'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + #'EQ_InvCostCE', + 'EQ_InvCostST', + #'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + 'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + 'EQ_EmiCO2Budget', + 'EQ_EmiCO2CapTra', + 'EQ_EmiCO2CapEle', + 'EQ_EmiCO2CapIndTE', + 'EQ_EmiCO2CapIndPro', + 'EQ_EmiCO2CapOth', + 'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios_orig/Correl_-0_5/src/openMASTER/output_data.py b/scenarios_orig/Correl_-0_5/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios_orig/Correl_-0_5/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios_orig/Correl_-0_5/src/openMASTER/scenarios.py b/scenarios_orig/Correl_-0_5/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios_orig/Correl_-0_5/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios_orig/Correl_-0_5/src/openMASTER/utils.py b/scenarios_orig/Correl_-0_5/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios_orig/Correl_-0_5/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios_orig/Correl_0_0/data/input/Data_Industrial.xlsx b/scenarios_orig/Correl_0_0/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..6c16429 --- /dev/null +++ b/scenarios_orig/Correl_0_0/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:453ebf662c132fc75ff1e45f0bab9847e7da232a1ac4271c9217274162df8d8d +size 152531 diff --git a/scenarios_orig/Correl_0_0/data/input/Data_Residential.xlsx b/scenarios_orig/Correl_0_0/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios_orig/Correl_0_0/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios_orig/Correl_0_0/data/input/costs_correl.csv b/scenarios_orig/Correl_0_0/data/input/costs_correl.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios_orig/Correl_0_0/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios_orig/Correl_0_0/data/input/covar.xlsx b/scenarios_orig/Correl_0_0/data/input/covar.xlsx new file mode 100644 index 0000000..8b555a3 --- /dev/null +++ b/scenarios_orig/Correl_0_0/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ca177f4b027253425ea04bed84b61b1de74b33c20d2189cfbd4593a3b1b846fd +size 78938 diff --git a/scenarios_orig/Correl_0_0/data/input/mean.csv b/scenarios_orig/Correl_0_0/data/input/mean.csv new file mode 100644 index 0000000..2fff9e5 --- /dev/null +++ b/scenarios_orig/Correl_0_0/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a91b8faab482cbdc4c145ae040244c3ffae0448ccb16ab87568d269b2dd1f0e3 +size 938 diff --git a/scenarios_orig/Correl_0_0/data/input/openMASTER_Data.xlsm b/scenarios_orig/Correl_0_0/data/input/openMASTER_Data.xlsm new file mode 100644 index 0000000..318866c --- /dev/null +++ b/scenarios_orig/Correl_0_0/data/input/openMASTER_Data.xlsm @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6dce092c8e1d2a5d6fdfa66a870dc530d57af874cc7c6d2283d692d40e15847d +size 3075435 diff --git a/scenarios_orig/Correl_0_0/data/input/openMASTER_Data.xlsx b/scenarios_orig/Correl_0_0/data/input/openMASTER_Data.xlsx new file mode 100644 index 0000000..910c5a0 --- /dev/null +++ b/scenarios_orig/Correl_0_0/data/input/openMASTER_Data.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7ef763d71a16579107012d88bf8b8c22637221276b1b47d98af1383a8bf2d876 +size 1236941 diff --git a/scenarios_orig/Correl_0_0/data/output/Results.xlsx b/scenarios_orig/Correl_0_0/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios_orig/Correl_0_0/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios_orig/Correl_0_0/src/openMASTER/Graphing_Tool/main.py b/scenarios_orig/Correl_0_0/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios_orig/Correl_0_0/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios_orig/Correl_0_0/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios_orig/Correl_0_0/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios_orig/Correl_0_0/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios_orig/Correl_0_0/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios_orig/Correl_0_0/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios_orig/Correl_0_0/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios_orig/Correl_0_0/src/openMASTER/Graphing_Tool/sankey.py b/scenarios_orig/Correl_0_0/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios_orig/Correl_0_0/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios_orig/Correl_0_0/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios_orig/Correl_0_0/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios_orig/Correl_0_0/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios_orig/Correl_0_0/src/openMASTER/GurobiShell.py b/scenarios_orig/Correl_0_0/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios_orig/Correl_0_0/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios_orig/Correl_0_0/src/openMASTER/__init__.py b/scenarios_orig/Correl_0_0/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios_orig/Correl_0_0/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios_orig/Correl_0_0/src/openMASTER/const.py b/scenarios_orig/Correl_0_0/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios_orig/Correl_0_0/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios_orig/Correl_0_0/src/openMASTER/execute_sankey.py b/scenarios_orig/Correl_0_0/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios_orig/Correl_0_0/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios_orig/Correl_0_0/src/openMASTER/loader.py b/scenarios_orig/Correl_0_0/src/openMASTER/loader.py new file mode 100644 index 0000000..70de7be --- /dev/null +++ b/scenarios_orig/Correl_0_0/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios_orig/Correl_0_0/src/openMASTER/model.py b/scenarios_orig/Correl_0_0/src/openMASTER/model.py new file mode 100644 index 0000000..667955f --- /dev/null +++ b/scenarios_orig/Correl_0_0/src/openMASTER/model.py @@ -0,0 +1,1835 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.f,m.sUnc, within=Reals, doc = '') + m.pAlpha_do = Param(m.f,m.sUnc, within=Reals, doc = '') + m.pRest = Param(m.f,m.sUnc, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[f,sPE] for f in m.f1) + sum(m.pRest[f,sPE] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[f,sCE] for f in m.f1) + sum(m.pRest[f,sCE] for f in m.fr)) for sCE in m.sCE ) + )) + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[f1,sPE] - m.pAlpha_do[f1,sPE]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[f1,sCE] - m.pAlpha_do[f1,sCE]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-2* m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + 'EQ_TotalCost_Unc', + 'EQ_UncCost', + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + 'EQ_InvCostCE_Unc', + 'EQ_OpCost_Unc', + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + #'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + #'EQ_InvCostCE', + 'EQ_InvCostST', + #'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + 'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + 'EQ_EmiCO2Budget', + 'EQ_EmiCO2CapTra', + 'EQ_EmiCO2CapEle', + 'EQ_EmiCO2CapIndTE', + 'EQ_EmiCO2CapIndPro', + 'EQ_EmiCO2CapOth', + 'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios_orig/Correl_0_0/src/openMASTER/output_data.py b/scenarios_orig/Correl_0_0/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios_orig/Correl_0_0/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios_orig/Correl_0_0/src/openMASTER/scenarios.py b/scenarios_orig/Correl_0_0/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios_orig/Correl_0_0/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios_orig/Correl_0_0/src/openMASTER/utils.py b/scenarios_orig/Correl_0_0/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios_orig/Correl_0_0/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/scenarios_orig/Correl_0_5/data/input/Data_Industrial.xlsx b/scenarios_orig/Correl_0_5/data/input/Data_Industrial.xlsx new file mode 100644 index 0000000..6c16429 --- /dev/null +++ b/scenarios_orig/Correl_0_5/data/input/Data_Industrial.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:453ebf662c132fc75ff1e45f0bab9847e7da232a1ac4271c9217274162df8d8d +size 152531 diff --git a/scenarios_orig/Correl_0_5/data/input/Data_Residential.xlsx b/scenarios_orig/Correl_0_5/data/input/Data_Residential.xlsx new file mode 100644 index 0000000..99fcdce --- /dev/null +++ b/scenarios_orig/Correl_0_5/data/input/Data_Residential.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86bec07f67893b3d5e3865ac3b7a240cf9d658f39e314a335d2b14281688d74b +size 314066 diff --git a/scenarios_orig/Correl_0_5/data/input/costs_correl.csv b/scenarios_orig/Correl_0_5/data/input/costs_correl.csv new file mode 100644 index 0000000..4f1bd06 --- /dev/null +++ b/scenarios_orig/Correl_0_5/data/input/costs_correl.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:777ace9e396ee1df823047c9bbf7b29c7ac93b7a1b4f6c184425d03e24b91026 +size 4209 diff --git a/scenarios_orig/Correl_0_5/data/input/covar.xlsx b/scenarios_orig/Correl_0_5/data/input/covar.xlsx new file mode 100644 index 0000000..332ebf0 --- /dev/null +++ b/scenarios_orig/Correl_0_5/data/input/covar.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f1efa254ea8baba652d379c6707c9bc4cd41f15bf38bd044c0a8e64aec9148a7 +size 78888 diff --git a/scenarios_orig/Correl_0_5/data/input/mean.csv b/scenarios_orig/Correl_0_5/data/input/mean.csv new file mode 100644 index 0000000..2fff9e5 --- /dev/null +++ b/scenarios_orig/Correl_0_5/data/input/mean.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a91b8faab482cbdc4c145ae040244c3ffae0448ccb16ab87568d269b2dd1f0e3 +size 938 diff --git a/scenarios_orig/Correl_0_5/data/input/openMASTER_Data.xlsm b/scenarios_orig/Correl_0_5/data/input/openMASTER_Data.xlsm new file mode 100644 index 0000000..318866c --- /dev/null +++ b/scenarios_orig/Correl_0_5/data/input/openMASTER_Data.xlsm @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6dce092c8e1d2a5d6fdfa66a870dc530d57af874cc7c6d2283d692d40e15847d +size 3075435 diff --git a/scenarios_orig/Correl_0_5/data/input/openMASTER_Data.xlsx b/scenarios_orig/Correl_0_5/data/input/openMASTER_Data.xlsx new file mode 100644 index 0000000..910c5a0 --- /dev/null +++ b/scenarios_orig/Correl_0_5/data/input/openMASTER_Data.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7ef763d71a16579107012d88bf8b8c22637221276b1b47d98af1383a8bf2d876 +size 1236941 diff --git a/scenarios_orig/Correl_0_5/data/output/Results.xlsx b/scenarios_orig/Correl_0_5/data/output/Results.xlsx new file mode 100644 index 0000000..983f86a --- /dev/null +++ b/scenarios_orig/Correl_0_5/data/output/Results.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1a65fe973832e63b7c6940b9e0026589c4fe7bc77926ded64e67a6db8f9df32b +size 42844288 diff --git a/scenarios_orig/Correl_0_5/src/openMASTER/Graphing_Tool/main.py b/scenarios_orig/Correl_0_5/src/openMASTER/Graphing_Tool/main.py new file mode 100644 index 0000000..f60303a --- /dev/null +++ b/scenarios_orig/Correl_0_5/src/openMASTER/Graphing_Tool/main.py @@ -0,0 +1,614 @@ +########### +# IMPORTS # +########### +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, font +from tkinter.font import families +from PIL import Image, ImageTk +from markdown2 import Markdown +from tkhtmlview import HTMLLabel +import customtkinter +import os +import json +import tempfile +import webbrowser +from sankey import create_sankey_diagram + +################### +# System Settings # +################### +customtkinter.set_appearance_mode("Light") +customtkinter.set_default_color_theme("blue") + +########### +# Sidebar # +########### +class Sidebar(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width=width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Input variables + self.width = width + + # Grid settings + self.grid_rowconfigure(4, weight=1) + + # Company's logo + logo_image = customtkinter.CTkImage(light_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), # Loading the logo image + dark_image=Image.open("Graphing_Tool\openMASTER_nobg.png"), + size=(self.width*0.7, self.width*0.35)) + self.logo_label = customtkinter.CTkLabel(self, image=logo_image, text="") # display image with a CTkLabel + self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10)) # Adding the logo label to the grid + + # Appeareance mode + self.appearance_mode_label = customtkinter.CTkLabel(self, text="Appearance Mode:", anchor="w") + self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0)) + self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self, values=["Light", "Dark"], + command=self.change_appearance_mode_event) + self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10)) + + # UI Scaling + self.scaling_label = customtkinter.CTkLabel(self, text="UI Scaling:", anchor="w") + self.scaling_label.grid(row=7, column=0, padx=20, pady=(10, 0)) + self.scaling_optionemenu = customtkinter.CTkOptionMenu(self, values=["80%", "90%", "100%", "110%", "120%"], + command=self.change_scaling_event) + self.scaling_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 20)) + + # Change UI Scaling Function + def change_scaling_event(self, new_scaling: str): + new_scaling_float = int(new_scaling.replace("%", "")) / 100 + customtkinter.set_widget_scaling(new_scaling_float) + + # Change Appearance Mode Function + def change_appearance_mode_event(self, new_appearance_mode: str): + customtkinter.set_appearance_mode(new_appearance_mode) + +################### +# Markdown Viewer # +################### +class MarkdownViewer(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Setting the font + self.font_style = font.Font(family="Helvetica", size=14) + + # Configure grid to expand + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + + # Converted output view + self.viewer = HTMLLabel(self, background="white") + self.viewer.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew") + + # Loading the input text + self.input_text = self.load_md_file("Graphing_Tool\sankey_description.txt" ) + + # Updating the output view + markdown_to_html = Markdown() + markdown_content = self.input_text + html_content = markdown_to_html.convert(markdown_content) + self.viewer.set_html(f'

{html_content}

') + + def load_md_file(self, filename): + try: + with open(filename, 'r') as file: + return file.read() + except Exception as e: + messagebox.showerror("File Error", f"Can't open file: {filename}") + +##################### +# Description Frame # +##################### +class Description_Frame(customtkinter.CTkFrame): + def __init__(self, master, width, *args, **kwargs): + super().__init__(master, width, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Get the initial appearance mode + self.appearance_mode = customtkinter.get_appearance_mode() + + # Input variables + self.master = master + self.width = width + + # Grid settings (2x1) + self.grid_columnconfigure((0), weight=1) + self.grid_rowconfigure(0, weight=2) + + # Description TextBox + self.description_textbox = MarkdownViewer(self) + self.description_textbox.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Load Data Button + self.loadData_btn = customtkinter.CTkButton(self, width=150, text="Load Data", command=self.check_data_load) + self.loadData_btn.grid(row=1, column=0, columnspan=1, padx=(20, 0), pady=(10, 0), sticky="w") + + # Check Load Label + self.check_label = tk.Label(self, text="") + self.check_label.grid(row=1, column=0, padx=(175,20), pady=(10, 0), sticky="w") + # Update the background color of the label + self.update_label_bg_color() + + # Check Data Load Function + def check_data_load(self): + self.master.sankey_data = self.load_json_data().copy() + if self.master.sankey_data is not None: + self.check_label.configure(text="✓", fg="green") + + # Json Data Load Function + def load_json_data(self): + file_path = filedialog.askopenfilename(filetypes=[('JSON Files', '*.json')]) + if file_path: + with open(file_path, 'r') as file: + data = json.load(file) + return data + else: + return None + + def update_label_bg_color(self): + fg_color = self.cget('fg_color') + if self.appearance_mode == "Light": + bg_color = fg_color[0] + else: + bg_color = fg_color[1] + self.check_label.configure(bg=bg_color) + +################## +# Units Selector # +################## +class UnitsSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4), weight=1) + + # Variable to hold the selected unit + self.selected_unit = tk.StringVar(value="TWh") + self.selected_unit.trace('w', self.clear_custom_entry) + + # Radio Buttons (Units Selection) + self.unit1_button = customtkinter.CTkRadioButton(self, text="TWh", variable=self.selected_unit, value="TWh") + self.unit2_button = customtkinter.CTkRadioButton(self, text="MWh", variable=self.selected_unit, value="MWh") + self.unit3_button = customtkinter.CTkRadioButton(self, text="KWh", variable=self.selected_unit, value="KWh") + + # Create the input box for custom unit + self.custom_unit_entry = customtkinter.CTkEntry(self) + self.custom_unit_label = customtkinter.CTkLabel(self, text="Other:") + + # Adding the buttons and entry to the grid + self.unit1_button.grid(row=0, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit2_button.grid(row=1, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.unit3_button.grid(row=2, column=0, padx=(20, 0), pady=(0, 10), sticky="nsew") + self.custom_unit_label.grid(row=3, column=0, padx=(20, 0), pady=(0, 0), sticky="w") + self.custom_unit_entry.grid(row=4, column=0, padx=(20, 0), pady=(0, 0), sticky="nsew") + + # Set an event to update the value of the custom radio button when text is entered + self.custom_unit_entry.bind('', self.update_custom_value) + + def update_custom_value(self, event): + custom_value = self.custom_unit_entry.get() + self.custom_unit_label['value'] = custom_value + if custom_value: + self.selected_unit.set(custom_value) + + def clear_custom_entry(self, *args): + if self.selected_unit.get() != self.custom_unit_entry.get(): + self.custom_unit_entry.delete(0, 'end') + +################## +# Color Selector # +################## +class ColorSelector(customtkinter.CTkFrame): + def __init__(self, master, color_label="Select Color Mode:", default_color="black", apply_btn=True, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Input Variables + self.color_label = color_label + self.default_color = default_color + self.apply_btn = apply_btn + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (5x2) + self.grid_columnconfigure(0, weight=0) + #self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3,4,5), weight=1) + + # List of predefined (preset) colors + predefined_colors = ['black', 'blue', 'brown', 'cyan', 'darkgray', 'gray', 'green', 'lightgray', 'magenta', 'orange', 'pink', 'purple', 'red', 'white', 'yellow'] + + # Default color selection mode + self.color_selection_mode = tk.StringVar(value="preset") + + # Label for color selection mode + self.selection_mode_label = customtkinter.CTkLabel(self, text=self.color_label) + self.selection_mode_label.grid(row=0, column=0, padx=(0, 0), pady=(0, 10), sticky="nsew") + + # Radio Buttons for color selection mode + self.preset_mode_button = customtkinter.CTkRadioButton(self, text="Preset Colors", variable=self.color_selection_mode, value="preset", command=self.toggle_color_selection_mode) + self.preset_mode_button.grid(row=1, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + self.hex_mode_button = customtkinter.CTkRadioButton(self, text="Hex Color", variable=self.color_selection_mode, value="hex", command=self.toggle_color_selection_mode) + self.hex_mode_button.grid(row=2, column=0, padx=(5, 0), pady=(0, 10), sticky="nsew") + + # Frame for predefined color selection + self.preset_color_frame = customtkinter.CTkFrame(self) + self.preset_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + self.preset_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # OptionMenu for predefined color selection + self.color_variable = tk.StringVar(self) + self.color_variable.set(self.default_color) + self.color_optionmenu = customtkinter.CTkOptionMenu(self.preset_color_frame, variable=self.color_variable, values=predefined_colors) + self.color_optionmenu.pack() + + # Frame for hex color input + self.hex_color_frame = customtkinter.CTkFrame(self) + self.hex_color_frame.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Label and Entry for hex color input + self.hex_entry = customtkinter.CTkEntry(self.hex_color_frame, placeholder_text="Enter Hex Color:") + self.hex_entry.pack() + + # Button to apply chosen color + self.apply_button = customtkinter.CTkButton(self, text="Apply", command=self.apply_color) + if apply_btn: + self.apply_button.grid(row=4, column=0, padx=(0, 0), pady=(0, 20), sticky="n") + + def toggle_color_selection_mode(self): + mode = self.color_selection_mode.get() + if mode == "preset": + self.hex_color_frame.grid_remove() + self.preset_color_frame.grid() + elif mode == "hex": + self.preset_color_frame.grid_remove() + self.hex_color_frame.grid(row=3, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew") + + def apply_color(self): + mode = self.color_selection_mode.get() + if mode == "preset": + color = self.preset_color_frame.winfo_children()[0].get() + self.configure(bg=color) + elif mode == "hex": + color = self.hex_color_frame.winfo_children()[1].get() + if color: + self.configure(bg=color) + +##################### +# Background Selector +##################### +class BackgroundSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (2x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=225) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Background Color Selectors + self.background_bg_selector = ColorSelector(self, color_label="Background Color Mode:", default_color="white", apply_btn=False) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 0), pady=(0, 20), sticky="w") + self.background_paper_selector = ColorSelector(self, color_label = "Paper Color Mode:", default_color="white", apply_btn=False) + self.background_paper_selector.grid(row=1, column=1, padx=(25, 0), pady=(0, 20), sticky="w") + + +################# +# Font Selector # +################# +class FontSelector(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (3x3) + self.grid_columnconfigure(0, weight=1, minsize=225) + self.grid_columnconfigure((1,2), weight=1, minsize=150) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + self.grid_rowconfigure(2, weight=2) + + # Available font families + font_families = families() + + # Option variable for font selection + self.select_font = tk.StringVar(value=font_families[0]) + + # Label for font selection + self.font_label = customtkinter.CTkLabel(self, text="Font Family:") + self.font_label.grid(row=0, column=0, padx=(20,0), pady=(0,10), sticky="w") + + # Label for font selection + self.font_optionmenu = customtkinter.CTkOptionMenu(self, variable=self.select_font, values=font_families) + self.font_optionmenu.grid(row=1, column=0, padx=(20,0), pady=(0,20), sticky="w") + + # Label for font size selection + self.size_label = customtkinter.CTkLabel(self, text="Font Size:") + self.size_label.grid(row=0, column=1, padx=(35,0), pady=(0,10), sticky="w") + + # Entry for font size input + self.size_entry = customtkinter.CTkEntry(self) + self.size_entry.insert(0, "10") # Set the default value to 10 + self.size_entry.grid(row=1, column=1, padx=(35,0), pady=(0,20), sticky="w") + + # Font Color Selection + self.font_color_selector = ColorSelector(self, color_label="Font Color Mode:", apply_btn=False) + self.font_color_selector.grid(row=0, column=2, rowspan=2,padx=(35,0), pady=(0,0), sticky="w") + +######################## +# General Config Frame # +######################## +class GeneralConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=3) + + # Configurations Tabs + self.config_tabview = customtkinter.CTkTabview(self) + self.config_tabview.add("Units") + self.config_tabview.add("Background") + self.config_tabview.add("Font") + self.config_tabview.grid(row=0, column=0, padx=(20, 20), pady=(0, 20), sticky="nsew") + + # Units Tab + self.units_selector = UnitsSelector(self.config_tabview.tab("Units")) + self.units_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + + # Background Tab + self.background_bg_selector = BackgroundSelector(self.config_tabview.tab("Background")) + self.background_bg_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="w") + + # Font Tab + self.font_selector = FontSelector(self.config_tabview.tab("Font")) + self.font_selector.grid(row=1, column=0, padx=(20, 20), pady=(20, 0), sticky="nsew") + +##################### +# Node Config Frame # +##################### +class NodeConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=1) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Node Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(20,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Node thickness selection + self.thickness_label = customtkinter.CTkLabel(self, text="Thickness:") + self.thickness_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.thickness_var = tk.IntVar(value=20) + self.thickness_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.thickness_entry.configure(textvariable=self.thickness_var) + self.thickness_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Node padding selection + self.padding_label = customtkinter.CTkLabel(self, text="Pad:") + self.padding_label.grid(row=3, column=0, padx=10, pady=(0,10), sticky="e") + + self.padding_var = tk.IntVar(value=15) + self.padding_entry = customtkinter.CTkEntry(self, validate="key", validatecommand=(self.register(self.validate_integer), "%P")) + self.padding_entry.configure(textvariable=self.padding_var) + self.padding_entry.grid(row=3, column=1, padx=10, pady=10, sticky="w") + + def validate_integer(self, value): + try: + if value: + int(value) + return True + except ValueError: + return False + +##################### +# Link Config Frame # +##################### +class LinkConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Initializing variables + self.sankey_data = None + + # Configuring the attributes of the frame + self.configure(fg_color=master.cget('fg_color'), border_width=0) + + # Grid settings (4x2) + self.grid_columnconfigure(0, weight=1) + self.grid_columnconfigure(1, weight=1) + self.grid_rowconfigure(0, weight=1) + self.grid_rowconfigure(1, weight=1) + self.grid_rowconfigure(2, weight=1) + self.grid_rowconfigure(3, weight=3) + + # Title label + self.title_label = customtkinter.CTkLabel(self, text="Border Configuration") + self.title_label.configure(font=("Helvetica", 12, "bold")) + self.title_label.grid(row=0, column=0, columnspan=2, padx=10, pady=(15,5)) + + # Separator line + self.separator = ttk.Separator(self, orient=tk.HORIZONTAL) + self.separator.grid(row=1, column=0, columnspan=2, sticky="ew") + + # Link width selection + self.width_label = customtkinter.CTkLabel(self, text="Width:") + self.width_label.grid(row=2, column=0, padx=10, pady=10, sticky="e") + + self.width_var = tk.IntVar(value=0.5) + self.width_entry = customtkinter.CTkEntry(self, validate="key") + self.width_entry.configure(textvariable=self.width_var) + self.width_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w") + + # Link Color Selection + self.line_color_selector = ColorSelector(self, color_label="Line Color Mode:", apply_btn=False) + self.line_color_selector.grid(row=3, column=0, columnspan=2,padx=(10,0), pady=(5,0), sticky="w") + +###################### +# Graph Config Frame # +###################### +class GraphConfigFrame(customtkinter.CTkFrame): + def __init__(self, master, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + # Configuring the attributes of the frame + self.configure(border_width=-2) + + # Grid settings (2x1) + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure((0,1,2,3), weight=1) + self.grid_rowconfigure((2,3), weight=2) + + # Node Configuration + self.node_config_frame = NodeConfigFrame(self) + self.node_config_frame.grid(row=0, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + + # Link Configuration + self.link_config_frame = LinkConfigFrame(self) + self.link_config_frame.grid(row=1, column=0, padx=(0, 20), pady=(0, 0), sticky="nsew") + +####### +# App # +####### +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + # App title + self.title("Graphing Tool") + + # Initializing variables + self.sankey_data = None + + ## Window settings + # Get screen width and height + screen_width = self.winfo_screenwidth() + screen_height = self.winfo_screenheight() + # Set window size (optional, to make the window a bit smaller than the screen size) + window_width = screen_width * 0.82 + window_height = screen_height * 0.80 + # Set window position (optional, to center the window) + position_top = int(screen_height / 2 - window_height / 2) + position_right = int(screen_width / 2 - window_width / 2) + # Set window geometry + self.geometry(f'{int(window_width)}x{int(window_height)}+{position_right}+{position_top}') + + # Grid settings (4x4) + self.grid_columnconfigure(0, weight=0) + self.grid_columnconfigure(1, weight=1, minsize=730) + self.grid_columnconfigure((2), weight=0) + self.grid_rowconfigure((0,1,2), weight=1) + + # Sidebar + self.sidebar_frame = Sidebar(self, width=200, corner_radius=0) + self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew") + + # Description Frame + self.description_frame = Description_Frame(self, width=100) + self.description_frame.grid(row=0, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # General Config Frame + self.general_config_frame = GeneralConfigFrame(self) + self.general_config_frame.grid(row=1, column=1, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Graph Config Frame + self.graph_config_frame = GraphConfigFrame(self) + self.graph_config_frame.grid(row=0, column=2, rowspan=2, padx=(0, 0), pady=(0, 0), sticky="nsew") + + # Plot Title Entry + self.plot_title_entry = customtkinter.CTkEntry(self, placeholder_text="Enter the Plot Title") + self.plot_title_entry.grid(row=3, column=1, columnspan=1, padx=(0, 0), pady=(20, 20), sticky="nsew") + + # Plot Button + self.plot_button = customtkinter.CTkButton(self, fg_color="transparent", border_width=2, text_color=("gray10", "#DCE4EE"), text="Plot Graph", command=self.generate_graph) + self.plot_button.grid(row=3, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew") + + + # Generate Sankey Diagram Function + def generate_graph(self): + + if self.sankey_data is None: + print("Please load all data before plotting.") + return + + # Retrieve the values from the input widgets + plot_title = self.plot_title_entry.get() + selected_unit = self.general_config_frame.units_selector.selected_unit.get() + font_family = self.general_config_frame.font_selector.select_font.get() + font_size = int(self.general_config_frame.font_selector.size_entry.get()) + node_thickness = int(self.graph_config_frame.node_config_frame.thickness_var.get()) + node_padding = int(self.graph_config_frame.node_config_frame.padding_var.get()) + link_width = int(self.graph_config_frame.link_config_frame.width_var.get()) + + # Retrieve the colors + bg_color = self.general_config_frame.background_bg_selector.background_bg_selector.color_variable.get() + paper_color = self.general_config_frame.background_bg_selector.background_paper_selector.color_variable.get() + font_color = self.general_config_frame.font_selector.font_color_selector.color_variable.get() + line_color = self.graph_config_frame.link_config_frame.line_color_selector.color_variable.get() + + # Loading the variables for the Sankey Diagram + sankey_data = self.sankey_data.copy() + node_labels = sankey_data['node_labels'] + node_colors = sankey_data['node_colors'] + link_sources = sankey_data['link_sources'] + link_targets = sankey_data['link_targets'] + link_values = sankey_data['link_values'] + link_colors = sankey_data['link_colors'] + link_labels = sankey_data['link_labels'] + + # Creating the Sankey Diagram + figure= create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors, + node_pad=node_padding, node_thickness=node_thickness, line_color=line_color, line_width=link_width, + font_size=font_size, font_color=font_color, font_family=font_family, + plot_bgcolor=bg_color, paper_bgcolor=paper_color, + plot_title = plot_title, units = selected_unit) + # Saving the figure to html and plottig it in the web browser + temp_html = os.path.join(tempfile.gettempdir(), "temp.html") + figure.write_html(temp_html) + webbrowser.open_new_tab('file://' + os.path.realpath(temp_html)) + + +app = App() +app.mainloop() + + \ No newline at end of file diff --git a/scenarios_orig/Correl_0_5/src/openMASTER/Graphing_Tool/openMASTER.png b/scenarios_orig/Correl_0_5/src/openMASTER/Graphing_Tool/openMASTER.png new file mode 100644 index 0000000..436ce91 Binary files /dev/null and b/scenarios_orig/Correl_0_5/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/scenarios_orig/Correl_0_5/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/scenarios_orig/Correl_0_5/src/openMASTER/Graphing_Tool/openMASTER_nobg.png new file mode 100644 index 0000000..2840568 Binary files /dev/null and b/scenarios_orig/Correl_0_5/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/scenarios_orig/Correl_0_5/src/openMASTER/Graphing_Tool/sankey.py b/scenarios_orig/Correl_0_5/src/openMASTER/Graphing_Tool/sankey.py new file mode 100644 index 0000000..d5b4a66 --- /dev/null +++ b/scenarios_orig/Correl_0_5/src/openMASTER/Graphing_Tool/sankey.py @@ -0,0 +1,65 @@ +########### +# IMPORTS # +########### + +import plotly.graph_objects as go + + +############# +# FUNCTIONS # +############# + +def create_sankey_diagram(source, target, value, node_labels, link_labels, node_colors, link_colors, + node_pad=15, node_thickness=20, line_color="black", line_width=0.5, + font_size=10, font_color="black", font_family="Arial", + plot_bgcolor="white", paper_bgcolor="white", + plot_title = "", units = "TWh"): + """ + Create a Sankey diagram using Plotly graph_objects. + + Args: + source (list): List of source node indices. + target (list): List of target node indices. + value (list): List of values representing the flow between source and target nodes. + node_labels (list): List of labels for each node. + link_labels (list): List of labels for each link. + node_colors (list): List of colors for each node. + link_colors (list): List of colors for each link. + + Returns: + plotly.graph_objects.Sankey: Sankey diagram object. + + """ + sankey = go.Sankey( + valueformat = ".0f", # Number Format + valuesuffix = units, # Energy Units + node=dict( + pad=node_pad, # Padding between nodes + thickness=node_thickness, # Thickness of the node + line=dict(color=line_color, width=line_width), # Node border line properties + label=node_labels, # Labels for each node + color=node_colors # Colors for each node + ), + link=dict( + source=source, # List of source node indices + target=target, # List of target node indices + value=value, # List of values representing the flow between source and target nodes + label=link_labels, # Labels for each link + color=link_colors # Colors for each link + ) + ) + + # Creating a Plotly Figure for the Sankey Diagram + figure = go.Figure(data=[sankey]) + + # Updating the Layout of the Plotly Figure + figure.update_layout( + hovermode = 'x', + title=plot_title, + font=dict(size = font_size, color = font_color, family= font_family), + plot_bgcolor=plot_bgcolor, + paper_bgcolor=paper_bgcolor + ) + + return figure +#------ \ No newline at end of file diff --git a/scenarios_orig/Correl_0_5/src/openMASTER/Graphing_Tool/sankey_description.txt b/scenarios_orig/Correl_0_5/src/openMASTER/Graphing_Tool/sankey_description.txt new file mode 100644 index 0000000..40536f2 --- /dev/null +++ b/scenarios_orig/Correl_0_5/src/openMASTER/Graphing_Tool/sankey_description.txt @@ -0,0 +1,13 @@ +# Key Variables to Modify in Sankey Diagrams + +When creating and customizing Sankey diagrams, several variables can be modified to enhance the visual representation and effectively convey the intended information. Some important variables include: + +**1. Node Thickness:** Modifying the thickness of nodes (represented as rectangles or segments) in the Sankey diagram can help emphasize the significance or volume of a specific flow or category. It allows for visual differentiation and highlights key elements in the system. + +**2.Node Padding:** Adjusting the padding or spacing between nodes can improve the clarity and organization of the diagram. Optimal padding ensures that nodes are visually separated and prevent overlapping, enhancing readability and understanding. + +**3.Link Width:** Changing the width of the links (represented as lines or arrows) connecting nodes can indicate the magnitude or intensity of the flow between different elements. Thicker links can represent larger quantities or stronger relationships, while thinner links can signify smaller flows. + +**4.Link Color:** Modifying the color of the links can provide additional information or categorization. Colors can be used to represent different types of flows, highlight specific patterns or trends, or differentiate between positive and negative relationships. + +**5.Background Color:** Choosing an appropriate background color for the Sankey diagram can influence the overall visual impact and readability. A well-chosen background color can enhance contrast, improve focus on the diagram elements, and create a harmonious visual composition. \ No newline at end of file diff --git a/scenarios_orig/Correl_0_5/src/openMASTER/GurobiShell.py b/scenarios_orig/Correl_0_5/src/openMASTER/GurobiShell.py new file mode 100644 index 0000000..5e89353 --- /dev/null +++ b/scenarios_orig/Correl_0_5/src/openMASTER/GurobiShell.py @@ -0,0 +1,23 @@ +from gurobipy import * +m=read('m_openMASTER_inst.lp') +m.printStats() +# m.setParam('getA()',) +# m.setParam('Method' ,2) +# m.setParam('Crossover',0) +# m.setParam('OutputFlag', 1) +# m.setParam('LogToConsole', 1) +# m.setParam('NumericFocus', 3) +# m.setParam('IISMethod', 0) +#m.setParam('BarHomogeneous', 1) +# m.setParam('FeasRelaxS', 0) +# m.feasRelaxS(2, False, False, True) +# # m.write('p2.lp') +# m=m.presolve() +# m.write('Model_264_PS.lp') + +#m.optimize() + +# m.printQuality() +# print(m.KappaExact) +m.computeIIS() +m.write('pp.ilp') diff --git a/scenarios_orig/Correl_0_5/src/openMASTER/__init__.py b/scenarios_orig/Correl_0_5/src/openMASTER/__init__.py new file mode 100644 index 0000000..5c158d6 --- /dev/null +++ b/scenarios_orig/Correl_0_5/src/openMASTER/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.0.0" +from openMASTER.model import make_model +from openMASTER.loader import load_dataportal_from_csv, excel_to_csv, load_dataportal_from_excel +from openMASTER.output_data import export_model_to_csv, import_results_from_csv +import openMASTER.utils diff --git a/scenarios_orig/Correl_0_5/src/openMASTER/const.py b/scenarios_orig/Correl_0_5/src/openMASTER/const.py new file mode 100644 index 0000000..dc460e2 --- /dev/null +++ b/scenarios_orig/Correl_0_5/src/openMASTER/const.py @@ -0,0 +1,11 @@ +import os +import os.path + +ROOTDIR = os.path.realpath(os.curdir) +PATH_DATA_IN = os.path.join(ROOTDIR, '../data/input') +PATH_MODEL_IN = os.path.join(ROOTDIR, '../data/tmp/input') +PATH_MODEL_OUT = os.path.join(ROOTDIR, '../data/tmp/output') +PATH_RESULTS = os.path.join(ROOTDIR, '../data/output') + +INDEX_FILENAME = os.path.join(PATH_MODEL_IN, 'INDEX.csv') + diff --git a/scenarios_orig/Correl_0_5/src/openMASTER/execute_sankey.py b/scenarios_orig/Correl_0_5/src/openMASTER/execute_sankey.py new file mode 100644 index 0000000..215a4d5 --- /dev/null +++ b/scenarios_orig/Correl_0_5/src/openMASTER/execute_sankey.py @@ -0,0 +1,386 @@ +# %% [markdown] +# ### **Imports** + +# %% +import pandas as pd +import os + +from charts_.sankey import create_sankey_diagram + + + +# %% [markdown] +# ### **Paths** + +# %% +MAPPINGS_DATA_PATH = "./data/tmp/mappings" +INPUT_DATA_PATH = "./data/tmp/input" +OUTPUT_DATA_PATH = "./data/tmp/output" + +# %% [markdown] +# ### **Functions** + +# %% +def sum_values_by_technology(df, selected_year, pe_column, ce_column, value_column): + # Select rows for the specified year + df_selected_year = df[df['sYear'] == selected_year] + + # Sum values by Technology and specified columns + sum_by_technology = df_selected_year.groupby([pe_column, ce_column])[value_column].sum().reset_index() + + return sum_by_technology + +# %% [markdown] +# ### **Data Preprocessing** + +# %% [markdown] +# **Set Mappings** + +# %% +sPE = pd.read_csv(MAPPINGS_DATA_PATH + "/sPE_mapping.csv") +SPE_dict = dict(zip(sPE['SPE'].values, sPE['DESCRIPTION'].values)) + +CEPri = pd.read_csv(MAPPINGS_DATA_PATH + "/CEPri_mapping.csv") +CEPri_dict = dict(zip(CEPri['SCE'].values, CEPri['Technology'].values)) + +CESec = pd.read_csv(MAPPINGS_DATA_PATH + "/CESec_mapping.csv") +CESec_dict = dict(zip(CESec['SCE'].values, CESec['Technology'].values)) + +TE = pd.read_csv(MAPPINGS_DATA_PATH + "/TE_mapping.csv") +TE_dict = dict(zip(TE['TE'].values, TE['Fuel'].values)) + +def assign_sector(sST): + if sST.startswith("sST_DSTRA"): + return "Transportation" + elif sST.startswith("sST_DSIND"): + return "Industry" + elif sST.startswith("sST_DSOTH"): + return "Residential and Commercial" + else: + return "Other" + +ST = pd.read_csv(os.path.join(INPUT_DATA_PATH,"sST.csv")) +ST["Sector"] = ST["sST"].apply(assign_sector) +ST_dict = dict(zip(ST['sST'].values, ST['Sector'].values)) + +# %% +selected_year = "2030" + +# %% [markdown] +# # **ENERGY Sankey** + +# %% [markdown] +# **PE-CEPri** / **CEPri-TE** + +# %% +# PE - CEPRI +# ========== +vQCEPriIN = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriIN.csv")) +vQCEPriIN['DESCRIPTION'] = vQCEPriIN['sPE'].map(SPE_dict) +vQCEPriIN['Technology'] = vQCEPriIN['sCE'].map(CEPri_dict) +vQCEPriIN['sYear'] = vQCEPriIN['sYear'].str[1:] + +pe_cepri= sum_values_by_technology(vQCEPriIN, selected_year, "DESCRIPTION", "Technology", "vQCEPriIN") + +# CEPRI - TE +# ========== +vQCEPriOUT = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEPriOUT.csv")) +vQCEPriOUT['Fuel'] = vQCEPriOUT['sTE'].map(TE_dict) +vQCEPriOUT['Technology'] = vQCEPriOUT['sCE'].map(CEPri_dict) +vQCEPriOUT['sYear'] = vQCEPriOUT['sYear'].str[1:] + +cepri_te= sum_values_by_technology(vQCEPriOUT, selected_year, "Fuel", "Technology", "vQCEPriOUT") + +# %% +# Dummies +# ======= +pe_cepri_dummy = pe_cepri[pe_cepri["Technology"].str.contains("Dummy")] +cepri_te_dummy = cepri_te[cepri_te["Technology"].str.contains("Dummy")] + +cepri_dummy = pd.merge(pe_cepri_dummy,cepri_te_dummy, on ="Technology")[["DESCRIPTION", "Fuel", "vQCEPriIN"]] + +# Dummy Nodes +cepri_dummy_nodes = list(cepri_dummy['DESCRIPTION'].values) +cepri_dummy_nodes.extend(list(cepri_dummy['Fuel'].values)) +cepri_dummy_values = list(cepri_dummy['vQCEPriIN'].values) + +# %% +# No Dummies +# ========== +pe_cepri = pe_cepri[~pe_cepri["Technology"].str.contains("Dummy")] +cepri_te = cepri_te[~cepri_te["Technology"].str.contains("Dummy")] + +# No Dummy Nodes +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vQCEPriIN'].values) + +cepri_te_nodes = list(cepri_te['Fuel'].values) +cepri_te_nodes.extend(list(cepri_te['Technology'].values)) +cepri_te_values = list(cepri_te['vQCEPriOUT'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vQCESecIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecIn.csv")) +vQCESecIn['Fuel'] = vQCESecIn['sTE'].map(TE_dict) +vQCESecIn['Technology'] = vQCESecIn['sCE'].map(CESec_dict) +vQCESecIn['sYear'] = vQCESecIn['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vQCESecIn, selected_year, "Technology", "Fuel", "vQCESecIN") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vQCESecIN'].values) + +# %% [markdown] +# **CESec-TE** + +# %% +vQCESecOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCESecOut.csv")) +vQCESecOut['Fuel'] = vQCESecOut['sTE'].map(TE_dict) +vQCESecOut['Technology'] = vQCESecOut['sCE'].map(CESec_dict) +vQCESecOut['sYear'] = vQCESecOut['sYear'].str[1:] + +cesec_te = sum_values_by_technology(vQCESecOut, selected_year, "Technology", "Fuel", "vQCESecOUT") + +# %% +cesec_te_nodes = list(cesec_te['Technology'].values) +cesec_te_nodes.extend(list(cesec_te['Fuel'].values)) + +cesec_te_values = list(cesec_te['vQCESecOUT'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vQCEStoIn = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoIn.csv")) +vQCEStoIn['Fuel'] = vQCEStoIn['sTE'].map(TE_dict) +vQCEStoIn['Technology'] = vQCEStoIn['sCE'].map(CESec_dict) +vQCEStoIn['sYear'] = vQCEStoIn['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vQCEStoIn, selected_year, "Technology", "Fuel", "vQCEStoIN") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vQCEStoIN'].values) + +# %% [markdown] +# **CE_Sto-TE** + +# %% +vQCEStoOut = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQCEStoOut.csv")) +vQCEStoOut['Fuel'] = vQCEStoOut['sTE'].map(TE_dict) +vQCEStoOut['Technology'] = vQCEStoOut['sCE'].map(CESec_dict) +vQCEStoOut['sYear'] = vQCEStoOut['sYear'].str[1:] + +cesto_te = sum_values_by_technology(vQCEStoOut, selected_year, "Technology", "Fuel", "vQCEStoOUT") + +# %% +cesto_te_nodes = list(cesto_te['Technology'].values) +cesto_te_nodes.extend(list(cesto_te['Fuel'].values)) + +cesto_te_values = list(cesto_te['vQCEStoOUT'].values) + +# %% [markdown] +# **TE-ST** + +# %% +vQSTInTE = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vQSTInTE.csv")) +vQSTInTE['Fuel'] = vQSTInTE['sTE'].map(TE_dict) +vQSTInTE['Sector'] = vQSTInTE['sST'].map(ST_dict) +vQSTInTE['sYear'] = vQSTInTE['sYear'].str[1:] +vQSTInTE.rename(columns={"vQSTInTE": "value"}, inplace=True) + +te_st = sum_values_by_technology(vQSTInTE, selected_year, "Fuel", "Sector", "value") + +# %% +te_st_nodes = list(te_st['Fuel'].values) +te_st_nodes.extend(list(te_st['Sector'].values)) + +te_st_values = list(te_st['value'].values) + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + cepri_te_nodes + te_cesec_nodes + cesec_te_nodes + te_cesto_nodes + cesto_te_nodes + te_st_nodes + cepri_dummy_nodes)) +link_values = pe_cepri_values + cepri_te_values + te_cesec_values + cesec_te_values + te_cesto_values + cesto_te_values + te_st_values + cepri_dummy_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(cepri_te_values)): + link_sources.append(node_labels.index(list(cepri_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cepri_te['Fuel'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(cesec_te_values)): + link_sources.append(node_labels.index(list(cesec_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesec_te['Fuel'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +for i in range(len(cesto_te_values)): + link_sources.append(node_labels.index(list(cesto_te['Technology'].values)[i])) + link_targets.append(node_labels.index(list(cesto_te['Fuel'].values)[i])) + +for i in range(len(te_st_values)): + link_sources.append(node_labels.index(list(te_st['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_st['Sector'].values)[i])) + +for i in range(len(cepri_dummy_values)): + link_sources.append(node_labels.index(list(cepri_dummy['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(cepri_dummy['Fuel'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +import json +with open('sankey_data.json', 'w') as f: + json.dump(sankey_data, f) + +# %% [markdown] +# ### **Plot** + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + +# %% [markdown] +# # **Emissions Sankey** + +# %% [markdown] +# **PE-CEPri** + +# %% +# PE - CEPRI +# ========== +vEmiCO2CEPri = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CEPri.csv")) +vEmiCO2CEPri['DESCRIPTION'] = vEmiCO2CEPri['sPE'].map(SPE_dict) +vEmiCO2CEPri['Technology'] = vEmiCO2CEPri['sCE'].map(CEPri_dict) +vEmiCO2CEPri['sYear'] = vEmiCO2CEPri['sYear'].str[1:] + +selected_year = "2020" +pe_cepri= sum_values_by_technology(vEmiCO2CEPri, selected_year, "DESCRIPTION", "Technology", "vEmiCO2CEPri") + +# %% +pe_cepri_nodes = list(pe_cepri['DESCRIPTION'].values) +pe_cepri_nodes.extend(list(pe_cepri['Technology'].values)) +pe_cepri_values = list(pe_cepri['vEmiCO2CEPri'].values) + +# %% [markdown] +# **TE-CESec** + +# %% +vEmiCO2CESec = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESec.csv")) +vEmiCO2CESec['Fuel'] = vEmiCO2CESec['sTE'].map(TE_dict) +vEmiCO2CESec['Technology'] = vEmiCO2CESec['sCE'].map(CESec_dict) +vEmiCO2CESec['sYear'] = vEmiCO2CESec['sYear'].str[1:] + +te_cesec = sum_values_by_technology(vEmiCO2CESec, selected_year, "Technology", "Fuel", "vEmiCO2CESec") + +# %% +te_cesec_nodes = list(te_cesec['Fuel'].values) +te_cesec_nodes.extend(list(te_cesec['Technology'].values)) + +te_cesec_values = list(te_cesec['vEmiCO2CESec'].values) + +# %% [markdown] +# **TE-CE_Sto** + +# %% +vEmiCO2CESto = pd.read_csv(os.path.join(OUTPUT_DATA_PATH,"vEmiCO2CESto.csv")) +vEmiCO2CESto['Fuel'] = vEmiCO2CESto['sTE'].map(TE_dict) +vEmiCO2CESto['Technology'] = vEmiCO2CESto['sCE'].map(CESec_dict) +vEmiCO2CESto['sYear'] = vEmiCO2CESto['sYear'].str[1:] + +te_cesto = sum_values_by_technology(vEmiCO2CESto, selected_year, "Technology", "Fuel", "vEmiCO2CESto") + +# %% +te_cesto_nodes = list(te_cesto['Technology'].values) +te_cesto_nodes.extend(list(te_cesto['Fuel'].values)) + +te_cesto_values = list(te_cesto['vEmiCO2CESto'].values) + +# %% [markdown] +# **TE-ST** + +# %% + + +# %% [markdown] +# ### Plot Preparation + +# %% +node_labels = list(set(pe_cepri_nodes + te_cesec_nodes + te_cesto_nodes)) +link_values = pe_cepri_values + te_cesec_values + te_cesto_values + +# %% +link_sources = [] +link_targets = [] + +for i in range(len(pe_cepri_values)): + link_sources.append(node_labels.index(list(pe_cepri['DESCRIPTION'].values)[i])) + link_targets.append(node_labels.index(list(pe_cepri['Technology'].values)[i])) + +for i in range(len(te_cesec_values)): + link_sources.append(node_labels.index(list(te_cesec['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesec['Technology'].values)[i])) + +for i in range(len(te_cesto_values)): + link_sources.append(node_labels.index(list(te_cesto['Fuel'].values)[i])) + link_targets.append(node_labels.index(list(te_cesto['Technology'].values)[i])) + +# %% +red_mappings= list(SPE_dict.values()) + list(TE_dict.values()) +node_colors = ['rgba(255,0,0,0.8)' if node in red_mappings else 'rgba(0,255,0,0.8)' for node in node_labels] + +# %% +node_colors = node_colors.copy() +link_colors = ["rgba(0,0,96,0.2)"] * len(link_values) +link_labels = [""] * len(link_values) + +sankey_data = {} +sankey_data['node_labels'] = node_labels +sankey_data['node_colors'] = node_colors +sankey_data['link_sources'] = link_sources +sankey_data['link_targets'] = link_targets +sankey_data['link_values'] = link_values +sankey_data['link_colors'] = link_colors +sankey_data['link_labels'] = link_labels + +# %% +create_sankey_diagram(link_sources, link_targets, link_values, node_labels, link_labels, node_colors, link_colors) + + diff --git a/scenarios_orig/Correl_0_5/src/openMASTER/loader.py b/scenarios_orig/Correl_0_5/src/openMASTER/loader.py new file mode 100644 index 0000000..70de7be --- /dev/null +++ b/scenarios_orig/Correl_0_5/src/openMASTER/loader.py @@ -0,0 +1,440 @@ +import os.path +import pandas as pd +from pyomo.environ import ( + DataPortal, +) + +from openMASTER.const import ( + PATH_MODEL_IN, + INDEX_FILENAME, +) + +def load_dataportal_from_excel(filename): + excel_to_csv(filename) + return load_dataportal_from_csv() + +def load_dataportal_from_csv() -> DataPortal: + + data = DataPortal() + + # Index config file path + index_path = os.path.join(PATH_MODEL_IN, "INDEX.csv") + + # Loading the INDEX config + index_config = pd.read_csv(index_path, index_col=0) + + # Loading Sets & Parameters to the DataPortal + sets_and_parameters = index_config[(index_config.TYPE == "Set") | (index_config.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + data_type = row["TYPE"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + #print(sheetname) + if dim_row==0 and dim_col==0: + # Index Names + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0] + else: + index_names = index_config[index_config["NAME"] == sheetname]['index_names'].values[0].split(",") + + # Loading the csv data to Data Portal + if data_type == "Set": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), set = sheetname, format = "set") + elif data_type == "Parameter": + filename = sheetname + '.csv' + data.load(filename = os.path.join(PATH_MODEL_IN, filename), index=index_names, param=[sheetname], format="table") + #indexed + + data._data[None] |= { + 'sQCEPriOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCEPri'][None] if (sCE,sTE) in data._data[None]['sQCEPriOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEPriOUT_CE_indexed' : {sCEPri : [(sCEPri,sTE) for sTE in data._data[None]['sTE' ][None] if (sCEPri,sTE) in data._data[None]['sQCEPriOUT'][None]] for sCEPri in data._data[None]['sCEPri'][None]}, + 'sQCESecOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sCE,sTE) in data._data[None]['sQCESecOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCESecOUT_CE_indexed' : {sCESec : [(sCESec,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESec,sTE) in data._data[None]['sQCESecOUT'][None]] for sCESec in data._data[None]['sCESec'][None]}, + 'sQCEStoOUT_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sCE,sTE) in data._data[None]['sQCEStoOUT'][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoOUT_CE_indexed' : {sCESto : [(sCESto,sTE) for sTE in data._data[None]['sTE' ][None] if (sCESto,sTE) in data._data[None]['sQCEStoOUT'][None]] for sCESto in data._data[None]['sCESto'][None]}, + 'sQCEPriIN_CE_indexed' : {sCE : [(sCE,sPE) for sPE in data._data[None]['sPE' ][None] if (sPE,sCE) in data._data[None]['sQCEPriIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCEStoIN_CE_indexed' : {sCE : [(sCE,sTE) for sTE in data._data[None]['sTE' ][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sCE in data._data[None]['sCE' ][None]}, + 'sQCESecIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESec'][None] if (sTE,sCE) in data._data[None]['sQCESecIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQCEStoIN_indexed' : {sTE : [(sTE,sCE) for sCE in data._data[None]['sCESto'][None] if (sTE,sCE) in data._data[None]['sQCEStoIN' ][None]] for sTE in data._data[None]['sTE' ][None]}, + 'sQSTOUT_indexed' : {sST : [(sST,sES) for sES in data._data[None]['sES' ][None] if (sST,sES) in data._data[None]['sQSTOUT' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sQSTInTE_indexed' : {sST : [(sST,sTE) for sTE in data._data[None]['sTE' ][None] if (sST,sTE) in data._data[None]['sQSTInTE' ][None]] for sST in data._data[None]['sST' ][None]}, + 'sVinYear_indexed' : {sYear : [(sYear,sVin) for sVin in data._data[None]['sVin' ][None] if (sVin,sYear) in data._data[None]['sVinYear' ][None]] for sYear in data._data[None]['sYear' ][None]}, + + 'sSTESVin_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin) + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sSTESVinTime_indexed' : {(sTE, sYear) : [(sTE,sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((( sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sTE in data._data[None]['sTE' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTVin_indexed' : {sYear: [(sYear,sST,sVin) + for sST in data._data[None]['sST' ][None] + for sVin in data._data[None]['sVin' ][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTInRM_indexed' : {sYear : [(sYear,sRM,sST,sES,sVin,sSeason,sDay,sHour) + for ( sRM,sST,sES) in data._data[None]['sQSTInRM' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + + }, + 'sQSTOUT_VinTime_indexed' : {sYear:[(sYear,sST,sES,sVin,sSeason,sDay,sHour) + for ( sST,sES) in data._data[None]['sQSTOUT' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_ST_ES_Year_indexed' : {(sST,sES,sYear):[(sST,sES,sYear,sVin,sSeason,sDay,sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if ((sVin,sYear) in data._data[None]['sVinYear' ][None]) + ] for sYear in data._data[None]['sYear' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sST,sES) in data._data[None]['sQSTOUT' ][None]) + }, + + 'sQSTOUT_STTraCar_ES_Year_indexed': {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra_Car,sVin,sSeason,sDay,sHour) + for sST_Tra_Car in data._data[None]['sST_Tra_Car' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra_Car,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_STTra_ES_Year_indexed' : {(sES_Tra,sYear):[(sES_Tra,sYear,sST_Tra,sVin,sSeason,sDay,sHour) + for sST_Tra in data._data[None]['sST_Tra' ][None] + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + if (((sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None]) and ((sVin,sYear) in data._data[None]['sVinYear'][None])) + ] for sES_Tra in data._data[None]['sES_Tra' ][None] + for sYear in data._data[None]['sYear' ][None] + }, + + 'sQSTOUT_Time_indexed' : {sYear: [(sYear,sST,sES,sSeason,sDay,sHour) + for (sST,sES) in data._data[None]['sQSTOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEPriOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCESecOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCESecOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEStoOUT_Time_indexed' : {sYear: [(sYear,sCE,sTE,sSeason,sDay,sHour) + for (sCE,sTE) in data._data[None]['sQCEStoOUT' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour'][None] + ] for sYear in data._data[None]['sYear' ][None] + }, + + 'sQCEPriIN_indexed' : {sPE : [(sPE,sCEPri) for sCEPri in data._data[None]['sCEPri'][None] if (sPE,sCEPri) in data._data[None]['sQCEPriIN'][None]] for sPE in data._data[None]['sPE'][None]}, + + 'sQTESTES_STES_indexed' : {(sST,sES): [(sST,sES,sTE) + for sTE in data._data[None]['sTE' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + ] for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + }, + + 'sQSTOUT_AFTra_indexed' : {sSD_Tra:[(sSD_Tra,sES_Tra,sST_Tra) + for ( sST_Tra,sES_Tra) in data._data[None]['sQSTOUT' ][None] + if (( sES_Tra,sSD_Tra) in data._data[None]['sQESSD' ][None]) + ] for sSD_Tra in data._data[None]['sSD_Tra' ][None] + }, + + 'sQSTOUT_AFTraCar_indexed' : {sSD_Tra_Car:[(sSD_Tra_Car,sES_Tra,sST_Tra_Car) + for ( sST_Tra_Car) in data._data[None]['sST_Tra_Car'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Car,sES_Tra,sSD_Tra_Car) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None] + }, + + 'sQSTOUT_AFTraBus_indexed' : {sSD_Tra_Bus:[(sSD_Tra_Bus,sES_Tra,sST_Tra_Bus) + for ( sST_Tra_Bus) in data._data[None]['sST_Tra_Bus'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Bus,sES_Tra,sSD_Tra_Bus) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Bus in data._data[None]['sSD_Tra_Bus'][None] + }, + + 'sQSTOUT_AFTraUrbRail_indexed' : {sSD_Tra_UrbanRail:[(sSD_Tra_UrbanRail,sES_Tra,sST_Tra_UrbanRail) + for ( sST_Tra_UrbanRail) in data._data[None]['sST_Tra_UrbanRail'][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_UrbanRail in data._data[None]['sSD_Tra_UrbanRail'][None] + }, + + 'sQSTOUT_AFTraIntRail_indexed' : {sSD_Tra_IntRail:[(sSD_Tra_IntRail,sES_Tra,sST_Tra_IntRail) + for ( sST_Tra_IntRail) in data._data[None]['sST_Tra_IntRail' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_IntRail in data._data[None]['sSD_Tra_IntRail' ][None] + }, + + 'sQSTOUT_AFTraMoped_indexed' : {sSD_Tra_Moped:[(sSD_Tra_Moped,sES_Tra,sST_Tra_Moped) + for ( sST_Tra_Moped) in data._data[None]['sST_Tra_Moped' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Moped,sES_Tra,sSD_Tra_Moped) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Moped in data._data[None]['sSD_Tra_Moped' ][None] + }, + + 'sQSTOUT_AFTraAir_indexed' : {sSD_Tra_Air:[(sSD_Tra_Air,sES_Tra,sST_Tra_Air) + for ( sST_Tra_Air) in data._data[None]['sST_Tra_Air' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Air,sES_Tra,sSD_Tra_Air) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Air in data._data[None]['sSD_Tra_Air' ][None] + }, + + 'sQSTOUT_AFTraSea_indexed' : {sSD_Tra_Sea:[(sSD_Tra_Sea,sES_Tra,sST_Tra_Sea) + for ( sST_Tra_Sea) in data._data[None]['sST_Tra_Sea' ][None] + for ( sES_Tra) in data._data[None]['sES_Tra' ][None] + if ((sST_Tra_Sea,sES_Tra,sSD_Tra_Sea) in data._data[None]['sQSTESSD' ][None]) + ] for sSD_Tra_Sea in data._data[None]['sSD_Tra_Sea' ][None] + }, + + 'sQSDMD_Tra_indexed' : {sSD_Tra : [(sSD_Tra,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra, sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra in data._data[None]['sSD_Tra' ][None]}, + + 'sQSDMD_Tra_Car_indexed' : {sSD_Tra_Car : [(sSD_Tra_Car,sMD_Tra) for sMD_Tra in data._data[None]['sMD_Tra'][None] if (sSD_Tra_Car,sMD_Tra) in data._data[None]['sQSDMD' ][None]] for sSD_Tra_Car in data._data[None]['sSD_Tra_Car'][None]}, + + 'sQSTOUT_AFOth_indexed' : {sES_Oth : [(sES_Oth,sST_Oth) for sST_Oth in data._data[None]['sST_Oth'][None] if (sST_Oth,sES_Oth ) in data._data[None]['sQSTOUT'][None]] for sES_Oth in data._data[None]['sES_Oth' ][None]}, + + 'sQSDMD_Oth_indexed' : {sES_Oth : [(sES_Oth,sSD_Oth,sMD_Oth) + for ( sSD_Oth,sMD_Oth) in data._data[None]['sQSDMD' ][None] + if (( sES_Oth,sSD_Oth) in data._data[None]['sQESSD' ][None]) + ] for sES_Oth in data._data[None]['sES_Oth' ][None] + }, + + 'sQSTOUT_AFInd_indexed' : {sSD_Ind:[(sSD_Ind,sES_Ind,sST_Ind) + for ( sST_Ind,sES_Ind) in data._data[None]['sQSTOUT' ][None] + if (( sES_Ind,sSD_Ind) in data._data[None]['sQESSD' ][None]) + ] for sSD_Ind in data._data[None]['sSD_Ind' ][None] + }, + + 'sQSDMD_Ind_indexed' : {sMD_Ind : [(sMD_Ind,sSD_Ind) for sSD_Ind in data._data[None]['sSD_Ind'][None] if (sSD_Ind,sMD_Ind) in data._data[None]['sQSDMD' ][None]] for sMD_Ind in data._data[None]['sMD_Ind'][None]}, + + 'sQSTOUT_sST_Cap' : {sST_Cap : [(sST_Cap,sES) for sES in data._data[None]['sES' ][None] if (sST_Cap,sES ) in data._data[None]['sQSTOUT'][None]] for sST_Cap in data._data[None]['sST_Cap'][None]}, + + 'sQSTOUT_sST_Uni' : {sST_Uni : [(sST_Uni,sES,sSeason,sDay,sHour) + for sES in data._data[None]['sES' ][None] + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (( sST_Uni,sES) in data._data[None]['sQSTOUT' ][None]) + ] for sST_Uni in data._data[None]['sST_Uni' ][None] + }, + + 'sQCEPriIN_YTime_indexed' : {(sPE,sCEPri,sYear):[(sPE,sCEPri,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sPE in data._data[None]['sPE' ][None] + for sCEPri in data._data[None]['sCEPri' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sPE,sCEPri) in data._data[None]['sQCEPriIN' ][None]) + }, + + 'sQCESecIN_YTime_indexed' : {(sTE,sCESec,sYear):[(sTE,sCESec,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESec in data._data[None]['sCESec' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESec) in data._data[None]['sQCESecIN' ][None]) + }, + + 'sQCEStoIN_YTime_indexed' : {(sTE,sCESto,sYear):[(sTE,sCESto,sYear,sSeason,sDay,sHour) + for (sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + ] for sTE in data._data[None]['sTE' ][None] + for sCESto in data._data[None]['sCESto' ][None] + for sYear in data._data[None]['sYear' ][None] + if ((sTE,sCESto) in data._data[None]['sQCEStoIN' ][None]) + }, + + 'sSTESTESVinTime_indexed' : {(sTE,sST,sES,sYear) : [(sTE,sST,sES,sYear,sVin, sSeason, sDay, sHour) + for sVin in data._data[None]['sVin' ][None] + for ( sSeason,sDay,sHour) in data._data[None]['sSeasonDayHour' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for sYear in data._data[None]['sYear' ][None] + for sTE in data._data[None]['sTE' ][None] + for sST in data._data[None]['sST' ][None] + for sES in data._data[None]['sES' ][None] + if ((sTE,sST,sES) in data._data[None]['sQTESTES' ][None]) + }, + + 'sTESTESVinTime_Ele_indexed' : {(sYear,sSeason, sDay, sHour) : [(sYear,sSeason,sDay,sHour,sTE,sST,sES,sVin) + for (sTE,sST,sES) in data._data[None]['sQTESTES_Ele' ][None] + for sVin in data._data[None]['sVin' ][None] + if (((sVin,sYear) in data._data[None]['sVinYear' ][None])) + ] for (sYear) in data._data[None]['sYear' ][None] + for (sSeason) in data._data[None]['sSeason' ][None] + for (sDay) in data._data[None]['sDay' ][None] + for (sHour) in data._data[None]['sHour' ][None] + }, + + } + + return data + +def excel_to_csv(excel_filepath): + """ + Conversión archivo de datos Excel a csv. + + INPUT + ===== + excel_filepath: Path to the Excel Input file + csv_filepath: Path to the csv Output file + + """ + # Loading the INDEX page + index_sheetname = "INDEX" + index_sheet = pd.read_excel(excel_filepath, sheet_name=index_sheetname) + + # Create new columnn to store the index names + index_sheet['index_names'] = None + index_sheet['index_names'] = index_sheet['index_names'].astype(object) + + # Getting the names of Sets and parameters + sets_and_parameters = index_sheet[(index_sheet.TYPE == "Set") | (index_sheet.TYPE == "Parameter")] + + for index, row in sets_and_parameters.iterrows(): + # Extracting Set & Parameters info from the INDEX Table + sheetname = row["NAME"] + dim_row = row["DIM_ROW"] + dim_col = row["DIM_COL"] + index_dim = [dim_row, dim_col] + + # Converting the Excel Table to csv + index_names = _excel_table_to_list(excel_filepath, sheetname, index_dim) + index_sheet.loc[index, 'index_names'] = ",".join(index_names) + + # Saving the Index Config File + index_sheet.to_csv(INDEX_FILENAME) + + +def _excel_table_to_list(path, sheetname, index_dim): + + # Número de índices de fila + n_row_index = index_dim[0] + # Número de índices de columna + n_col_index = index_dim[1] + + # Realizamos una carga preliminar del archivo excel para determinar el comienzo y final de los datos + raw_data = pd.read_excel(path, sheet_name = sheetname, header = None) + # Buscamos la posición de aquellas celdas que delimiten los márgenes de los datos (KEYWORD: ~BOUNDS~) + raw_data = pd.melt(raw_data.reset_index(), id_vars=['index']) + is_bounds = raw_data['value'] == "~BOUNDS~" + bounds = raw_data.loc[is_bounds, ['index', 'variable']].sort_values(['index', 'variable']) + # Cambiamos el nombre de las columnas + bounds.columns = ['row', 'column'] + + # Extraemos los márgenes de los datos + # Recordar que los índice de Python empiezan en 0. Si quisieramos extraer el número de fila o columna real, debemos sumarle 1 a los valores propuestos. + start_row = min(bounds['row']) # Fila inicial + end_row = max(bounds['row']) # Fila final + start_col = min(bounds['column']) + 1 # Columna inicial + end_col = max(bounds['column']) - 1 # Columna final + + # Cargamos la tabla de datos con los márgenes delimitados anteriormente + data = pd.read_excel(path, sheet_name = sheetname, skiprows=start_row, header=list(range(0,max(1,n_col_index)))).iloc[:end_row-(start_row+max(0,n_col_index-1)),start_col:end_col+1] + + # Nombres de todos los índices + index_names = list(data.columns[list(range(0,n_row_index))]) + + # Nombres de los índices de las filas y columnas + if n_col_index == 0: + # Nombres de los índices de las filas + row_index_names = index_names + # Nombres de los índices de las columas + col_index_names = [] + elif n_col_index == 1: + # Nombres de los índices de las filas + row_index_names = [name.split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [index_names[0].split("/")[1].strip()] + elif n_col_index > 1: + # Nombres de los índices de las filas + row_index_names = [name[-1].split("/")[0].strip() for name in index_names] + # Nombres de los índices de las columnas + col_index_names = [name.split("/")[0].strip() for name in index_names[0][:-1]] + [index_names[0][-1].split("/")[1].strip()] + + # Nombre de las columnas (que no son indices) + param_column_names = list(data.columns)[n_row_index:] + + # Nombre de los Sets (indices) + set_names = row_index_names + col_index_names + + # Si se trata de un parámetro, existirá una columna de valores + if len(param_column_names) > 0: + + # Dataframe donde ir añadiendo los datos reformateados + new_columns = set_names + [sheetname] + data_list = pd.DataFrame(columns = new_columns) + + # Dataframe temporal para ir almacenando el valor de los indices y sus parametros + # Inicializamos el Dataframe con el valor de los índices de las filas + temp_values = pd.DataFrame(data.iloc[:,list(range(0,n_row_index))]) + temp_values.columns = temp_values.columns.to_flat_index() + temp_values.columns = row_index_names + + # Extraemos los valores de las columnas (que no son indices) + for i in range(len(param_column_names)): + # Nombre de la columna actual + current_column = param_column_names[i] + # Extraemos SOLO la columna actual + current_column_values = pd.DataFrame(data[current_column]) + # Extraemos los valores de los índices de las columnas + if n_col_index == 0: + col_index_values = [] + elif n_col_index == 1: + col_index_values = list(current_column_values.columns) + elif n_col_index > 1: + col_index_values = list(current_column_values.columns)[0] + # Añadimos los valores de los índices de las columnas al Dataframe temporal + for i in range(len(col_index_values)): + temp_values[col_index_names[i]] = col_index_values[i] + # Añadimos el valor de los parámetros + temp_values[sheetname] = current_column_values.values + # Rellenamos los valores de los parámetros vacíos con 0.0 + temp_values[sheetname].fillna(0.0, inplace = True) + # Concatenamos los datos obtenidos a la lista de datos final (data_list) + data_list = pd.concat([data_list, temp_values], ignore_index=True) + + # Si se trata de un Set, NO existirá una columna de valores + else: + # Creamos un Dataframe con la información de los índices del Set + data_list = data.copy() + + # Path del fichero a exportar + filename=sheetname+".csv" + out_filename = os.path.join(PATH_MODEL_IN, filename) + # Exportado de los datos en formato .csv + os.makedirs(os.path.dirname(out_filename), exist_ok=True) + data_list.to_csv(out_filename, index = False) + + return set_names diff --git a/scenarios_orig/Correl_0_5/src/openMASTER/model.py b/scenarios_orig/Correl_0_5/src/openMASTER/model.py new file mode 100644 index 0000000..dfe5226 --- /dev/null +++ b/scenarios_orig/Correl_0_5/src/openMASTER/model.py @@ -0,0 +1,1835 @@ +from pyomo.environ import ( + AbstractModel, + Set, + Param, + Var, + Reals, + NonNegativeReals, + Objective, + Constraint, + minimize, + quicksum, +) + +def make_model(): + m = AbstractModel('openMASTER') + + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) + m.sTE = Set ( doc = "Final Energy Commodities" ) + m.sRM = Set ( doc = "Raw Materials Commodities" ) + m.sST = Set ( doc = "Energy Service Supply Technologies" ) + m.sES = Set ( doc = "Energy Service Commodities" ) + m.sSD = Set ( doc = "Service Demand Commodities" ) + m.sBM = Set ( doc = "Behavioural Measures" ) + m.sDM = Set ( doc = "Demand Shift Measures" ) + m.sMD = Set ( doc = "Macro Data" ) + + m.sVin = Set (ordered = True , doc = "Vintage years" ) + m.sSeason = Set (ordered = True , doc = "Representative seasons/months of the year" ) + m.sDay = Set (ordered = True , doc = "Representative days of the season/month" ) + m.sHour = Set (ordered = True , doc = "Representative hours for a representive day" ) + m.sSeasonDayHour = Set (within=m.sSeason*m.sDay*m.sHour , doc= "m.sSeason*m.sDay*m.sHour" ) + m.sAge = Set (ordered = True , doc = "sAge" ) + + #Subset + m.sPE_Nuc = Set (within=m.sPE, doc = "Nuclear Primary Energy Commodities" ) + m.sPE_Fossil = Set (within=m.sPE, doc = "Fossil Primary Energy Commodities" ) + m.sPE_Renew = Set (within=m.sPE, doc = "Renewable Primary Energy Commodities" ) + + m.sCEPri = Set (within=m.sCE, doc = "Conversion Energy Technologies with PE input" ) + m.sCESec = Set (within=m.sCE, doc = "Conversion Energy Technologies with TE input" ) + m.sCESto = Set (within=m.sCE, doc = "Storage Energy Technologies" ) + m.sCE_Nuc = Set (within=m.sCE, doc = "Nuclear Energy Technologies" ) + m.sCE_Hydro = Set (within=m.sCE, doc = "Hydro Energy Technologies" ) + m.sCE_Coal = Set (within=m.sCE, doc = "Coal Energy Technologies" ) + m.sCE_Var = Set (within=m.sCE, doc = "Variable Energy Technologies" ) + m.sCE_Ele = Set (within=m.sCE, doc = "Electricity Energy Technologies" ) + m.sCE_Ref = Set (within=m.sCE, doc = "Refine Energy Technologies" ) + + m.sTE_Ele = Set (within=m.sTE, doc = "Electricity Final Energy Commodities" ) + + m.sST_Tra = Set (within=m.sST, doc = "Transportation Supply Technologies" ) + m.sModes = Set ( doc = "Transportation Modes" ) + m.sST_Tra_Car = Set (within=m.sST, doc = "Transportation Supply Technologies. Car" ) + m.sST_Tra_Air = Set (within=m.sST, doc = "Transportation Supply Technologies. Air" ) + m.sST_Tra_Bus = Set (within=m.sST, doc = "Transportation Supply Technologies. Bus" ) + m.sST_Tra_IntRail = Set (within=m.sST, doc = "Transportation Supply Technologies. IntRail" ) + m.sST_Tra_Moped = Set (within=m.sST, doc = "Transportation Supply Technologies. Moped" ) + m.sST_Tra_RoadFreight = Set (within=m.sST, doc = "Transportation Supply Technologies. RoadFreight" ) + m.sST_Tra_Sea = Set (within=m.sST, doc = "Transportation Supply Technologies. Sea" ) + m.sST_Tra_UrbanRail = Set (within=m.sST, doc = "Transportation Supply Technologies. UrbanRail" ) + m.sST_Oth = Set (within=m.sST, doc = "Others Supply Technologies" ) + m.sST_Ind = Set (within=m.sST, doc = "Industrial Supply Technologies" ) + + m.sST_Cap = Set (within=m.sST, doc = "Supply Technologies measured by capacity units" ) + m.sST_Uni = Set (within=m.sST, doc = "Supply Technologies measured by number of units" ) + + m.sES_Tra = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Tra_Car = Set (within=m.sES, doc = "Transportation Energy Service Commodities" ) + m.sES_Oth = Set (within=m.sES, doc = "Others Energy Service Commodities" ) + m.sES_Ind = Set (within=m.sES, doc = "Industrial Energy Service Commodities" ) + + m.sBM_Tra = Set (within=m.sBM, doc = "Behavioural Measures in Transportation" ) + m.sBM_Oth = Set (within=m.sBM, doc = "Behavioural Measures in Others" ) + + m.sDM_Tra = Set (within=m.sDM, doc = "Demand Shift Measures in Transportation" ) + m.sDM_Oth = Set (within=m.sDM, doc = "Demand Shift Measures in Others" ) + + m.sSD_Tra = Set (within=m.sSD, doc = "Transportation Service Demand Commodities" ) + m.sSD_Tra_Car = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Car" ) + m.sSD_Tra_Moped = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Moped" ) + m.sSD_Tra_Bus = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Bus" ) + m.sSD_Tra_Air = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Air" ) + m.sSD_Tra_Sea = Set (within=m.sSD, doc = "Transportation Service Demand Commodities Sea" ) + m.sSD_Tra_UrbanRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities UrbanRail" ) + m.sSD_Tra_IntRail = Set (within=m.sSD, doc = "Transportation Service Demand Commodities IntRail" ) + m.sSD_Tra_RoadFreight = Set (within=m.sSD, doc = "Transportation Service Demand Commodities RoadFreight" ) + m.sSD_Oth = Set (within=m.sSD, doc = "Others Service Demand Commodities" ) + m.sSD_Oth_HE = Set (within=m.sSD, doc = "Others Service Demand Commodities. High Efficiency" ) + m.sSD_Oth_LE = Set (within=m.sSD, doc = "Others Service Demand Commodities. Low Efficiency" ) + m.sSD_Ind = Set (within=m.sSD, doc = "Industrial Service Demand Commodities" ) + + m.sMD_Tra = Set (within=m.sMD, doc = "Transportation Macro Data Commodities" ) + m.sMD_Oth = Set (within=m.sMD, doc = "Others Macro Data Commodities" ) + m.sMD_Ind = Set (within=m.sMD, doc = "Industrial Macro Data Commodities" ) + + m.sYear = Set (within=m.sVin, doc = "Optimization years period" ) + m.sYearBNZ = Set (within=m.sVin, doc = "Before Net-Zero emissions target year period" ) + m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) + m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) + m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) + + #Relational sets + m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) + m.sQCESecIN = Set (within=m.sTE*m.sCESec, doc = "Input TE to Secondary CE" ) + m.sQCEStoIN = Set (within=m.sTE*m.sCESto, doc = "Input TE to Storage CE" ) + + m.sQCEPriOUT = Set (within=m.sCEPri*m.sTE, doc = "Primary CE to Output TE" ) + m.sQCESecOUT = Set (within=m.sCESec*m.sTE, doc = "Secondary CE to Output TE" ) + m.sQCEStoOUT = Set (within=m.sCESto*m.sTE, doc = "Storage CE to Output TE" ) + + m.sQSTInTE = Set (within=m.sTE*m.sST, doc = "Input TE to ST" ) + m.sQSTInRM = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES " ) + m.sQSTInRM_Cir = Set (within=m.sRM*m.sST*m.sES, doc = "Input RM to ST producing ES. Circularity") + m.sQSTOUT = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Tra = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Oth = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQSTOUT_Ind = Set (within=m.sST*m.sES, doc = " ST to Output ES" ) + m.sQTESTES = Set (within=m.sTE*m.sST*m.sES, doc = " TE to ST to ES relational set" ) + m.sQTESTES_Ele = Set (within=m.sTE*m.sST*m.sES, doc = " Electr (TE)to ST to ES relational set" ) + m.sQTESTES_Ind = Set (within=m.sTE*m.sST*m.sES, doc = " Industry(TE)to ST to ES relational set" ) + m.sQESSD = Set (within=m.sES*m.sSD, doc = " ES to SD" ) + m.sQSTESSD = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD" ) + m.sQSTESSD_Tra = Set (within=m.sST*m.sES*m.sSD, doc = " ST to ES to SD. Transportation" ) + m.sQESSDMD_Oth = Set (within=m.sES*m.sSD*m.sMD, doc = " ES to SD to MD. Others" ) + m.sQSDMD = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Res = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Oth = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + m.sQSDMD_Tra = Set (within=m.sSD*m.sMD, doc = " SD to MD" ) + + m.sVinYear = Set (within=m.sVin*m.sYear, doc = " Vin-Year " ) + + + #Specific sets + m.sTime = m.sYear*m.sSeason*m.sDay*m.sHour + m.sVinTime = m.sVinYear*m.sSeason*m.sDay*m.sHour + m.sYearTime = m.sSeason*m.sDay*m.sHour + m.sPEYearTime = m.sPE*m.sSeason*m.sDay*m.sHour + + #Dictionaries + m.sQCEPriOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecOUT_indexed = Set(m.sTE, dimen=2) + m.sQCEStoOUT_indexed = Set(m.sTE, dimen=2) + m.sQCESecIN_indexed = Set(m.sTE, dimen=2) + m.sQCEStoIN_indexed = Set(m.sTE, dimen=2) + m.sSTESVin_indexed = Set(m.sTE, m.sYear, dimen=5) + m.sQSTInRM_indexed = Set(m.sYear, dimen=8) + m.sQSTVin_indexed = Set(m.sYear, dimen=3) + m.sQSTOUT_VinTime_indexed = Set(m.sYear, dimen=7) + m.sQSTOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCESecOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEStoOUT_Time_indexed = Set(m.sYear, dimen=6) + m.sQCEPriIN_indexed = Set(m.sPE, dimen=2) + m.sQCEPriOUT_CE_indexed = Set(m.sCEPri, dimen=2) + m.sQCESecOUT_CE_indexed = Set(m.sCESec, dimen=2) + m.sQCEStoOUT_CE_indexed = Set(m.sCESto, dimen=2) + m.sQTESTES_STES_indexed = Set(m.sST,m.sES, dimen=3) + m.sQSTOUT_indexed = Set(m.sST, dimen=2) + m.sVinYear_indexed = Set(m.sYear, dimen=2) + m.sQSTOUT_AFTra_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSDMD_Tra_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSDMD_Tra_Car_indexed = Set(m.sSD_Tra, dimen=2) + m.sQSTOUT_AFOth_indexed = Set(m.sES_Oth, dimen=2) + m.sQSDMD_Oth_indexed = Set(m.sES_Oth, dimen=3) + m.sQSTOUT_AFInd_indexed = Set(m.sSD_Ind, dimen=3) + m.sQSDMD_Ind_indexed = Set(m.sMD_Ind, dimen=2) + m.sQSTOUT_sST_Cap = Set(m.sST_Cap, dimen=2) + m.sQSTOUT_sST_Uni = Set(m.sST_Uni, dimen=5) + m.sQCEPriIN_YTime_indexed = Set(m.sPE,m.sCEPri,m.sYear, dimen=6) + m.sQCESecIN_YTime_indexed = Set(m.sTE,m.sCESec,m.sYear, dimen=6) + m.sQCEStoIN_YTime_indexed = Set(m.sTE,m.sCESto,m.sYear, dimen=6) + m.sQCEPriIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCESecIN_CE_indexed = Set(m.sCE, dimen=2) + m.sQCEStoIN_CE_indexed = Set(m.sCE, dimen=2) + m.sSTESVinTime_indexed = Set(m.sTE,m.sYear, dimen=8) + m.sSTESTESVinTime_indexed = Set(m.sTE,m.sST,m.sES,m.sYear, dimen=8) + m.sQSTOUT_ST_ES_Year_indexed = Set(m.sST,m.sES,m.sYear, dimen=7) + m.sTESTESVinTime_Ele_indexed = Set(m.sYear,m.sSeason,m.sDay,m.sHour, dimen=8) + m.sQSTOUT_STTraCar_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_STTra_ES_Year_indexed = Set(m.sES_Tra,m.sYear, dimen=7) + m.sQSTOUT_AFTraCar_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraBus_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraUrbRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraIntRail_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraMoped_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraAir_indexed = Set(m.sSD_Tra, dimen=3) + m.sQSTOUT_AFTraSea_indexed = Set(m.sSD_Tra, dimen=3) + + # Parameter definition + m.pYr = Param(m.sVin, doc = 'Year number' ) + m.pYrGap = Param( doc = 'Representative year gap' ) + m.pTimeSlice = Param(m.sSeason, m.sDay, m.sHour, doc = 'Time slice load factor' ) + m.pNumHours = Param( doc = 'Number of hours in the time slice' ) + m.pDisRate = Param( doc = 'Discount Rate' ) + m.pGreenfield = Param( doc = 'GreenField=1 | BrownField=0' ) + m.pEmiCO2CapSectRestr= Param( doc = 'CO2 Emission Sectorial Cap=1 | CO2 Emission Global Cap=0' ) + m.pEmiCO2BudgetRestr = Param( doc = 'CO2 Emission Budget =1 | CO2 Emission Cap =0' ) + m.pEmiCO2Cost = Param(m.sYear, doc = 'CO2 emission cost [€ per tCO2 ]') + + m.pCEResMar = Param( doc = 'Required reserve margin over peak demand, for adequacy restriction' ) + m.pCEDemErr = Param( doc = 'Average prediction error in demand, for reserves restriction' ) + m.pCEAFErr = Param( doc = 'Average prediction error in CE modelled with load factors, for reserves restriction' ) + m.pCEFailProb = Param( doc = 'Larger CE failure probability to be considered for reserves restriction' ) + m.pCEFailCap = Param( doc = 'Larger CE capacity to be considered for reserves restriction (GW of the largest plant that can fail)' ) + + + #Emissions + + ##Global emission constraints + m.pEmiCO2Budget = Param( doc = 'CO2 emission budget' ) + m.pEmiCO2Cap = Param(m.sYear, doc = 'CO2 emission cap per year' ) + m.pEmiNOxCap = Param(m.sYear, doc = 'NOx emission cap per year' ) + m.pEmiSOxCap = Param(m.sYear, doc = 'SOx emission cap per year' ) + m.pEmiPM25Cap = Param(m.sYear, doc = 'PM25 emission cap per year' ) + ##Sectorial CO2 constraints + m.pEmiCO2CapTra = Param(m.sYear, doc = 'Transport sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapEle = Param(m.sYear, doc = 'Electricity generation CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndTE = Param(m.sYear, doc = 'Industrial sector (energy) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapIndPro = Param(m.sYear, doc = 'Industrial sector (process) CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapOth = Param(m.sYear, doc = 'Residential&Service sector CO2 emission cap per year [MtCO2 ]') + m.pEmiCO2CapRef = Param(m.sYear, doc = 'Refinery sector CO2 emission cap per year [MtCO2 ]') + ##CO2 + m.pEmiCO2CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2CESto = Param(m.sTE,m.sCE, doc = 'Storage CE CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2TE = Param(m.sTE, doc = 'TE transportation CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STTE = Param(m.sST,m.sTE, doc = 'TE consumption CO2 emission factor [tCO2 per MWh ]') + m.pEmiCO2STPro = Param(m.sST,m.sES, doc = 'Process emission CO2 emission factor [tCO2 per ES unit ]') + m.pEmiCO2ESNS = Param( doc = 'ENS CO2 emission factor [tCO2 per ES unit ]') + ##NOx + m.pEmiNOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption NOx emission factor [tNOx per MWh ]') + m.pEmiNOxSTPro = Param(m.sST,m.sES, doc = 'Process emission NOx emission factor [tNOx per ES unit ]') + m.pEmiNOxESNS = Param( doc = 'ENS NOx emission factor [tNOx per ES unit ]') + ##SOx + m.pEmiSOxCEPri = Param(m.sPE,m.sCE, doc = 'Primary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESec = Param(m.sTE,m.sCE, doc = 'Secondary CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxCESto = Param(m.sTE,m.sCE, doc = 'Storage CE SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTTE = Param(m.sST,m.sTE, doc = 'TE consumption SOx emission factor [tSOx per MWh ]') + m.pEmiSOxSTPro = Param(m.sST,m.sES, doc = 'Process emission SOx emission factor [tSOx per ES unit ]') + m.pEmiSOxESNS = Param( doc = 'ENS SOx emission factor [tSOx per ES unit ]') + ##PM25 + m.pEmiPM25CEPri = Param(m.sPE,m.sCE, doc = 'Primary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESec = Param(m.sTE,m.sCE, doc = 'Secondary CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25CESto = Param(m.sTE,m.sCE, doc = 'Storage CE PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STTE = Param(m.sST,m.sTE, doc = 'TE consumption PM25 emission factor [tPM25 per MWh ]') + m.pEmiPM25STPro = Param(m.sST,m.sES, doc = 'Process emission PM25 emission factor [tPM25 per ES unit ]') + m.pEmiPM25ESNS = Param( doc = 'ENS PM25 emission factor [tPM25 per ES unit ]') + + #ESNS + m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.f,m.sUnc, within=Reals, doc = '') + m.pAlpha_do = Param(m.f,m.sUnc, within=Reals, doc = '') + m.pRest = Param(m.f,m.sUnc, within=Reals, doc = '') + + #PE Primary Energy characterization + m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') + m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') + m.pPEImpCap = Param(m.sPE, doc = 'PE importation capacity [GW ]') + + #CE Conversion technologies characterization + m.pCEOutShareMin = Param( m.sCE,m.sTE, doc = 'Minimum Output share [% ]') + m.pCEOutShareMax = Param( m.sCE,m.sTE, doc = 'Maximum Output share [% ]') + m.pSTTra_MS = Param( m.sModes,m.sSD, doc = 'Modal Shares (calibration year) [% ]') + m.pCEPriEff = Param(m.sPE,m.sCE, doc = 'CEPri Efficiency factor [% ]') + m.pCESecEff = Param(m.sTE,m.sCE, doc = 'CESec Efficiency factor [% ]') + m.pCEStoEff = Param(m.sTE,m.sCE, doc = 'CESto Efficiency factor [% ]') + m.pCELife = Param( m.sCE, doc = 'Life of energy technologies [years ]') + m.pCEInsCap = Param( m.sCE, doc = 'Previous installed capacity of CE [GW ]') + m.pCEMaxCap = Param( m.sCE, doc = 'Maximum installed capacity of CE [GW ]') + m.pCEStoCap = Param( m.sCE, doc = 'Storage capacity in terms of energy [MWh ]') + m.pCECapex = Param( m.sCE, m.sYear, doc = 'CAPEX of CE [€ per kW ]') + m.pCEDecom = Param( m.sCE, m.sYear, doc = 'Decommission cost of CE [€ per kW ]') + m.pCEFixom = Param( m.sCE, doc = 'Fixed O&M costs of CE [€ per kW ]') + m.pCEVarom = Param( m.sCE,m.sTE, doc = 'Variable O&M costs of CE [€ per MWh ]') + m.pCEReact = Param( m.sCE, m.sYear, doc = 'Reactivation cost of CE [€ per kW ]') + m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') + m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') + m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') + + #TE Transformed energy characterization + m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') + + #RM Raw materials characterization + m.pRMCost = Param(m.sRM,m.sYear, doc = 'RM cost [€ per ton ]') + m.pRMCircular = Param(m.sES,m.sRM, doc = 'RM circularity rate [% ]') + + #ST technologies characterization + m.pSTOutShareMin = Param(m.sST,m.sES, doc = 'ST Outshare minimum [% ]') + m.pSTOutShareMax = Param(m.sST,m.sES, doc = 'ST Outshare maximum [% ]') + m.pMSMax = Param( doc = 'Maximum modal shift [% ]') + m.pTCMax = Param( doc = 'Maximum technological choice [% ]') + m.pSTEffTE = Param(m.sST,m.sES,m.sTE,m.sVin, doc = 'ST efficiency [GWh per ES units ]') + m.pSTEffRM = Param(m.sRM,m.sST,m.sES, doc = 'RM input [RM units per ES units]') + m.pSTInsCap = Param(m.sST,m.sVin, doc = 'ST previous installed capacity [ST units ]') + m.pSTMaxCap = Param(m.sST, doc = 'ST maximum allowed capacity [ST units ]') + m.pSTMaxPro = Param(m.sST, doc = 'Maximum ST annual production [ES units ]') + m.pSTCapex = Param(m.sST,m.sYear, doc = 'ST CAPEX cost [G€ per ST unit ]') + m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') + m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') + m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') + + #Activity factors + m.pAFTra = Param(m.sST,m.sES,m.sSD, doc = 'Activity factor (Occupancy Rate) Transportation [% ]') + m.pAFOth = Param(m.sES,m.sSD,m.sMD, doc = 'Activity factor (ES demand per dwelling/km2) [ES units ]') + m.pAFInd = Param(m.sES,m.sSD, doc = 'Activity factor (none) [% ]') + #Behavioural Measures + m.pBMCost = Param(m.sBM,m.sYear, doc = 'Behavioural Measures Cost [G€ per AF unit ]') + m.pDeltaAFTra = Param(m.sST,m.sES,m.sSD, m.sBM, doc = 'Behavioural Measures max improvement allowed (Occupancy Rate) in Transportation [% ]') + m.pDeltaAFOth = Param( m.sES,m.sSD,m.sMD,m.sBM, doc = 'Behavioural Measures max improvement allowed (ES demand) in Others [ES units ]') + m.pTW = Param( m.sES,m.sSD,m.sMD, doc = 'Remote work: Trade-off between residental energy service increase and transportation demand decrease [ES unit per Mpkm ]') + + #Demand shit Measures + m.pDMCost = Param(m.sDM,m.sYear, doc = 'Demand shift Measures Cost [G€ per DC unit ]') + m.pDeltaDC = Param(m.sSD,m.sMD, m.sDM, doc = 'Demand shift Measures max improvement allowed [% ]') + + # Demand characterization and Macro data + m.pDC = Param(m.sSD,m.sMD, doc = 'Demand characterization [DC unit ]') + m.pMD = Param(m.sMD,m.sYear, doc = 'Macro data [MD unit ]') + + + # Variables definition + + #O.F. Variables + m.vSysCost = Var ( within = Reals, doc = "Total System cost [G€ ]") + m.vTotalCost = Var ( m.sYear, within = Reals, doc = "Annual Total cost [G€ ]") + m.vBMCost = Var ( m.sBM, m.sYear, within = Reals, doc = "Annual Behavioural Measures cost [G€ ]") + m.vDMCost = Var ( m.sDM, m.sYear, within = Reals, doc = "Annual Demand shift Measures cost [G€ ]") + m.vPenalCost = Var ( m.sYear, within = Reals, doc = "Annual Penalization cost [G€ ]") + m.vInvCostCE = Var ( m.sCE, m.sYear, within = Reals, doc = "Annual Total CE investment cost [G€ ]") + m.vInvCostST = Var ( m.sST, m.sYear, within = Reals, doc = "Annual Total ST investment cost [G€ ]") + m.vOpCost = Var ( m.sYear, within = Reals, doc = "Annual Total operation cost [M€ ]") + m.vOpVarom = Var ( m.sYear, within = Reals, doc = "Annual Total Varom cost [k€ ]") + + + #Origin of PE - variables + m.vQPEDom = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE domestic consumption [GWh ]") + m.vQPEImp = Var (m.sPE, m.sTime, within = NonNegativeReals, doc = "PE imports [GWh ]") + + #CE conversion technologies using PE commodities - var iables + m.vQCEPriIN = Var ( m.sQCEPriIN, m.sTime, within = NonNegativeReals, doc = "PE consumed by CE techs [GWh ]") + m.vQCEPriOUT = Var ( m.sQCEPriOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from PE energy [GWh ]") + + #CE conversion technologies using TE commodities - var iables + m.vQCESecIN = Var ( m.sQCESecIN, m.sTime, within = NonNegativeReals, doc = "TE consumed by CE techs [GWh ]") + m.vQCESecOUT = Var ( m.sQCESecOUT, m.sTime, within = NonNegativeReals, doc = "TE produced in CE techs from TE energy [GWh ]") + + #Storage technologies using TE commodities - variables + m.vQCEStoIN = Var ( m.sQCEStoIN, m.sTime, within = NonNegativeReals, doc = "TE stored by Storage techs") + m.vQCEStoOUT = Var ( m.sQCEStoOUT, m.sTime, within = NonNegativeReals, doc = "TE released in Storage techs from TE energy [GWh ]") + + m.vCEStoLevel = Var ( m.sCESto, m.sTime, within = NonNegativeReals, doc = "Accumulated energy stored in Storage processes [GWh ]") + + #TE transport energy losses - variables + m.vQTELoss = Var ( m.sTE, m.sTime, within = NonNegativeReals, doc = "TE losses in transportation processes [GWh ]") + + #ST balance - variables + m.vQSTInTE = Var ( m.sQTESTES, m.sVinTime, within = NonNegativeReals, doc = "TE consumed by ST [GWh ]") + m.vQSTInRM = Var ( m.sQSTInRM, m.sVinTime, within = NonNegativeReals, doc = "RM consumed by ST (industrial) [Tons ]") + m.vQSTOut = Var ( m.sQSTOUT, m.sVinTime, within = NonNegativeReals, doc = "ES produced by ST [ES units ]") + + #ES + m.vQESNS = Var ( m.sQSTOUT, m.sTime, within = NonNegativeReals, doc = "ES not supplied (slack variable) [ES units ]") + m.vQES = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "ES [ES units ]") + + #BM + m.vBMTra = Var ( m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Transportation [ES units ]") + m.vBMOth = Var ( m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others [ES units ]") + m.vBMOth_WAMAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Washing Machine [ES units ]") + m.vBMOth_DIWAC = Var ( m.sQSDMD_Oth,m.sBM_Oth,m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Cold cycle Dish Washer [ES units ]") + m.vBMOth_TW = Var ( m.sQESSDMD_Oth, m.sYear, within = NonNegativeReals, doc = "Behavioural Measures. Others. Telework [ES units ]") + + #SD + m.vQSDTra = Var ( m.sSD_Tra, m.sYear, within = NonNegativeReals, doc = "Transportation SD [SD units ]") + m.vQSDOth = Var ( m.sSD_Oth,m.sMD_Oth, m.sYear, within = NonNegativeReals, doc = "Others SD [SD units ]") + m.vQSDInd = Var ( m.sSD_Ind, m.sYear, within = NonNegativeReals, doc = "Industrial SD [SD units ]") + + #DM + m.vDMTra = Var ( m.sQSDMD_Tra,m.sDM_Tra,m.sYear, within = NonNegativeReals, doc = "DMTra [SD units ]") + m.vDMOth_HE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_HE [SD units ]") + m.vDMOth_LE = Var ( m.sMD_Oth, m.sDM_Oth,m.sYear, within = NonNegativeReals, doc = "DMOth_LE [SD units ]") + + + #CE capacity variables + m.vCENewCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE new installed capacity [GW ]") + m.vCETotCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE accumulated installed capacity [GW ]") + m.vCEDecCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE decommisioned capacity [GW ]") + m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") + m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") + m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") + + m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") + m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") + + + #ST capacity variables + m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") + m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") + m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") + + #CO2 Emission variables + m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") + m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") + m.vEmiCO2CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Secondary CE processes [ktCO2 ]") + m.vEmiCO2CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Storage CE processes [ktCO2 ]") + m.vEmiCO2TE = Var ( m.sTE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in the transportation of TE [ktCO2 ]") + m.vEmiCO2STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to TE consumption [ktCO2 ]") + m.vEmiCO2STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST due to activity processes [ktCO2 ]") + m.vEmiCO2ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in ST [ktCO2 ]") + m.vEmiCO2ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "CO2 emissions related to ESNS [ktCO2 ]") + m.vEmiCO2Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Annual Total CO2 emissions [MtCO2 ]") + m.vEmiCO2CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap 2050 onwards (slack variable) [MtCO2 ]") + m.vEmiCO2BudgetExc = Var ( within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Budget (slack variable) [MtCO2 ]") + + #NOx Emission variables + m.vEmiNOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in CE processes [ktNOx ]") + m.vEmiNOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Primary CE processes [ tNOx ]") + m.vEmiNOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Secondary CE processes [ tNOx ]") + m.vEmiNOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in Storage CE processes [ tNOx ]") + m.vEmiNOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to TE consumption [ tNOx ]") + m.vEmiNOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST due to activity processes [ tNOx ]") + m.vEmiNOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "NOx emissions produced in ST [ktNOx ]") + m.vEmiNOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "NOx emissions related to ESNS [ktNOx ]") + m.vEmiNOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total NOx emissions produced yearly [MtNOx ]") + m.vEmiNOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of NOx emissions regarding cap 2050 onwards (slack variable) [MtNOx ]") + + #SOx Emission variables + m.vEmiSOxCE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in CE processes [ktSOx ]") + m.vEmiSOxCEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Primary CE processes [ tSOx ]") + m.vEmiSOxCESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Secondary CE processes [ tSOx ]") + m.vEmiSOxCESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in Storage CE processes [ tSOx ]") + m.vEmiSOxSTTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to TE consumption [ tSOx ]") + m.vEmiSOxSTPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST due to activity processes [ tSOx ]") + m.vEmiSOxST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "SOx emissions produced in ST [ktSOx ]") + m.vEmiSOxESNS = Var ( m.sYear, within = NonNegativeReals, doc = "SOx emissions related to ESNS [ktSOx ]") + m.vEmiSOxTot = Var ( m.sYear, within = NonNegativeReals, doc = "Total SOx emissions produced yearly [MtSOx ]") + m.vEmiSOxCapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of SOx emissions regarding cap 2050 onwards (slack variable) [MtSOx ]") + + #PM25 Emission variables + m.vEmiPM25CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in CE processes [ktPM25 ]") + m.vEmiPM25CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Primary CE processes [ tPM25 ]") + m.vEmiPM25CESec = Var (m.sQCESecIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Secondary CE processes [ tPM25 ]") + m.vEmiPM25CESto = Var (m.sQCEStoIN, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in Storage CE processes [ tPM25 ]") + m.vEmiPM25STTE = Var ( m.sQTESTES, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to TE consumption [ tPM25 ]") + m.vEmiPM25STPro = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST due to activity processes [ tPM25 ]") + m.vEmiPM25ST = Var ( m.sQSTOUT, m.sYear, within = NonNegativeReals, doc = "PM25 emissions produced in ST [ktPM25 ]") + m.vEmiPM25ESNS = Var ( m.sYear, within = NonNegativeReals, doc = "PM25 emissions related to ESNS [ktPM25 ]") + m.vEmiPM25CapExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of PM25 emissions regarding cap 2050 onwards (slack variable) [MtPM25 ]") + m.vEmiPM25Tot = Var ( m.sYear, within = NonNegativeReals, doc = "Total PM25 emissions produced yearly [MtPM25 ]") + + + #CO2 sectorial emission slack variables + m.vEmiCO2CapTraExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Transport sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapEleExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Electricity generation (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndTEExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (energy) (slack variable) [MtCO2 ]") + m.vEmiCO2CapIndProExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Industrial sector (process) (slack variable) [MtCO2 ]") + m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") + m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") + + #Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + d = dict() + + # ### **Equations** + # #### Objective function + + #Objective function + def EQ_FObj (m ): + return (m.vSysCost) + d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') + + ##### Constraints + + + + + # Uncertainty eqs + + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[f,sPE] for f in m.f1) + sum(m.pRest[f,sPE] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[f,sCE] for f in m.f1) + sum(m.pRest[f,sCE] for f in m.fr)) for sCE in m.sCE ) + )) + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[f1,sPE] - m.pAlpha_do[f1,sPE]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[f1,sCE] - m.pAlpha_do[f1,sCE]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + + + + # Objective function-related constraints + + + def EQ_SysCost (m ): + return m.vSysCost == (sum(m.vTotalCost [sYear] for sYear in m.sYear) + + sum(m.vPenalCost [sYear] for sYear in m.sYear) + + sum(m.vBMCost [sBM,sYear] for (sBM, sYear) in m.sBM*m.sYear) + + sum(m.vDMCost [sDM,sYear] for (sDM, sYear) in m.sDM*m.sYear) + + m.pEmiCO2BudgetRestr * m.vEmiCO2BudgetExc + ) + #G€ + d['EQ_SysCost'] = Constraint( rule = EQ_SysCost, doc = 'Total System Cost [G€]') + + + def EQ_PenalCost (m, sYear ): + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-2* m.pESNSCost * ( + + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) + ) + #G€ + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + + + def EQ_TotalCost (m, sYear ): + return m.vTotalCost[sYear] == (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost'] = Constraint(m.sYear, rule = EQ_TotalCost, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_BMCost (m, sBM,sYear ): + return m.vBMCost[sBM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pBMCost[sBM,sYear] * m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM,sYear] for (sST_Tra,sES_Tra,sSD_Tra) in m.sQSTESSD_Tra if sBM in m.sBM_Tra) + + sum(m.pBMCost[sBM,sYear] * m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM,sYear] for (sES_Oth,sSD_Oth,sMD_Oth) in m.sQESSDMD_Oth if sBM in m.sBM_Oth) + ) + #G€ + d['EQ_BMCost'] = Constraint(m.sBM,m.sYear, rule = EQ_BMCost, doc = 'Annual BM Cost [G€]') + + + + def EQ_DMCost (m, sDM,sYear ): + return m.vDMCost[sDM,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + sum(m.pDMCost [sDM, sYear] * m.vDMTra [sSD_Tra,sMD_Tra,sDM,sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra if sDM in m.sDM_Tra) + + sum(m.pDMCost [sDM, sYear] * (m.vDMOth_HE[ sMD_Oth,sDM,sYear] + - (m.vDMOth_HE[sMD_Oth,sDM,m.sYear.prev(sYear)] if not sYear==m.sYear.first() else 0)) for sMD_Oth in m.sMD_Oth if sDM in m.sDM_Oth) + ) + #G€ + d['EQ_DMCost'] = Constraint(m.sDM,m.sYear, rule = EQ_DMCost, doc = 'Annual DM Cost [G€]') + + + + def EQ_InvCostCE (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCECapex[sCE,sYear] * m.vCENewCap [sCE,sYear] + + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + + + + def EQ_InvCostST (m, sST, sYear ): + return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pSTCapex[sST,sYear] * m.vSTNewCap [sST, sYear] + + m.pSTDecom[sST,sYear] * sum(m.vSTDecCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + ) *1e-3 + #G€ + d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') + + + + def EQ_OpCost (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + + + + def EQ_OpVarom (m, sYear ): + return m.vOpVarom[sYear] == ( + + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEPriOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEPriOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCESecOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCESecOUT_Time_indexed[sYear]) + + sum(m.pCEVarom[sCE,sTE] * (m.vQCEStoOUT[sCE,sTE,sYear,sSeason,sDay,sHour]) for (_,sCE,sTE,sSeason,sDay,sHour) in m.sQCEStoOUT_Time_indexed[sYear]) + + ) + #k€ + d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + + + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + + # Primary energy (PE)-related constraints + + + def EQ_PEDomCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEDomCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEDom [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEDomCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEDomCap, doc = 'PE domestic production capacity [GWh]') + + + def EQ_PEImpCap (m, sPE, sYear, sSeason, sDay, sHour ): + return m.pPEImpCap [sPE] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_PEImpCap'] = Constraint(m.sPE,m.sTime, rule = EQ_PEImpCap, doc = 'PE importation capacity [GWh]') + + + def EQ_PEBalance (m, sPE, sYear, sSeason, sDay, sHour ): + return m.vQPEDom[sPE,sYear,sSeason,sDay,sHour] + m.vQPEImp[sPE,sYear,sSeason,sDay,sHour] == sum(m.vQCEPriIN[sPE,sCE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriIN_indexed[sPE]) + #GWh + d['EQ_PEBalance'] = Constraint(m.sPE,m.sTime, rule = EQ_PEBalance, doc = 'PE energy balance [GWh]') + + + # Primary Conversion Energy (CE_Pri)-related contraints + + + def EQ_CEPriBalance (m, sCEPri, sYear, sSeason, sDay, sHour ): + return (sum(((m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] if (sPE,sCEPri) in m.sQCEPriIN else 0) * (m.pCEPriEff[sPE, sCEPri] if (sPE,sCEPri) in m.sQCEPriIN else 0)) for sPE in m.sPE) + == sum(( m.vQCEPriOUT[sCEPri,sTE,sYear,sSeason,sDay,sHour] if (sCEPri,sTE) in m.sQCEPriOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CEPriBalance'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEPriBalance, doc = 'Balance for Primary CE techs (using PE commodities) [GWh]') + + + def EQ_CEPriOutShareMin (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEPriOutShareMin'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CEPriOutShareMax (m, sCEPri,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCEPri,sTE] * sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) >= m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEPriOutShareMax'] = Constraint(m.sQCEPriOUT,m.sTime, rule = EQ_CEPriOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Secondary Conversion Energy (CE_Sec)-related constraints + + + def EQ_CESecBalance (m, sCESec,sYear,sSeason,sDay,sHour ): + return (sum(((m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] if (sTE,sCESec) in m.sQCESecIN else 0) * (m.pCESecEff[sTE, sCESec] if (sTE, sCESec) in m.sQCESecIN else 0)) for sTE in m.sTE) + == sum(( m.vQCESecOUT[sCESec,sTE,sYear,sSeason,sDay,sHour] if (sCESec,sTE) in m.sQCESecOUT else 0) for sTE in m.sTE)) + #GWh + d['EQ_CESecBalance'] = Constraint(m.sCESec,m.sTime, rule = EQ_CESecBalance, doc = 'Balance for CE techs using TE commodities [GWh]') + + + def EQ_CESecOutShareMin (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CESecOutShareMin'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMin, doc = 'Minimum CE output shares restriction [GWh]') + + + def EQ_CESecOutShareMax (m, sCESec,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax[sCESec,sTE] * sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) >= m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CESecOutShareMax'] = Constraint(m.sQCESecOUT,m.sTime, rule = EQ_CESecOutShareMax, doc = 'Maximum CE output shares restriction [GWh]') + + + # Storage-related constraints + + + def EQ_CEStoBalance (m, sCESto,sYear,sSeason ): + return (sum((m.vQCEStoIN [sTE,sCESto,sYear,sSeason,sDay,sHour] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if ((sTE,sCESto) in m.sQCEStoIN )) + == sum( m.vQCEStoOUT[sCESto,sTE,sYear,sSeason,sDay,sHour] for (sTE,sDay,sHour) in m.sTE*m.sDay*m.sHour if (sCESto,sTE) in m.sQCEStoOUT)) + #GWh (Seasonal balance) + d['EQ_CEStoBalance'] = Constraint(m.sCESto,m.sYear,m.sSeason, rule = EQ_CEStoBalance, doc = 'Balance for storage seasonal representative-day [GWh]') + + + def EQ_CEStoLevel (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, sHour] ==( + + (m.vCEStoLevel [ sCESto, sYear,sSeason, sDay, m.sHour.prev(sHour)] if not sHour==m.sHour.first() else 0) # if h>00 --> level(d , h-1 ) + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.prev(sDay),m.sHour.last() ] if (sHour==m.sHour.first() and not sDay==m.sDay.first()) else 0) # if d>0 and h=00 --> level(d-1 , h.l + + (m.vCEStoLevel [ sCESto, sYear,sSeason,m.sDay.last() ,m.sHour.last() ] if (sHour==m.sHour.first() and sDay==m.sDay.first()) else 0) # if d=0 and h=00 --> level(d.last, h.last) + + sum((m.vQCEStoIN [sTE,sCESto, sYear,sSeason, sDay, sHour ] * (m.pCEStoEff[sTE, sCESto] if (sTE, sCESto) in m.sQCEStoIN else 0)) for sTE in m.sTE if ((sTE,sCESto) in m.sQCEStoIN)) + - sum(m.vQCEStoOUT [ sCESto,sTE,sYear,sSeason, sDay, sHour ] for sTE in m.sTE if ((sCESto,sTE) in m.sQCEStoOUT))) + #GWh + d['EQ_CEStoLevel'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoLevel, doc = 'Storage level calculation [GWh]') + + + def EQ_CEStoOutShareMin (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] >= m.pCEOutShareMin [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEStoOutShareMin'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMin, doc = 'Minimum Storage output shares [GWh]') + + + def EQ_CEStoOutShareMax (m, sCESto,sTE,sYear,sSeason,sDay,sHour ): + return m.pCEOutShareMax [sCESto,sTE] * sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) >= m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoOutShareMax'] = Constraint(m.sQCEStoOUT,m.sTime, rule = EQ_CEStoOutShareMax, doc = 'Maximum Storage output shares [GWh]') + + + def EQ_CEStoMaxSto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.pCEStoCap [sCESto] >= m.vCEStoLevel [sCESto,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_CEStoMaxSto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEStoMaxSto, doc = 'Storage maximum level restriction [GWh]') + + + # Transported Energy (TE)-related constraints + + + # TE + + def EQ_TEBalance (m, sTE,sYear,sSeason,sDay,sHour ): + + return (quicksum(m.vQCEPriOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE] ) + + quicksum(m.vQCESecOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE] ) + + quicksum(m.vQCEStoOUT [sCE,sTE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE] ) + - quicksum(m.vQCESecIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecIN_indexed [sTE] ) + - quicksum(m.vQCEStoIN [sTE,sCE, sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoIN_indexed [sTE] ) + - m.vQTELoss [sTE, sYear,sSeason,sDay,sHour] + >= quicksum(m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin) in m.sSTESVin_indexed [sTE, sYear])) + #GWh + d['EQ_TEBalance'] = Constraint(m.sTE,m.sTime, rule = EQ_TEBalance, doc = 'Balance for TE [GWh]') + + + def EQ_TELoss (m, sTE,sYear,sSeason,sDay,sHour ): + return (m.vQTELoss [sTE,sYear,sSeason,sDay,sHour] == m.pTELoss[sTE] * ( + sum(m.vQCEPriOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEPriOUT_indexed[sTE]) + + sum(m.vQCESecOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCESecOUT_indexed[sTE]) + + sum(m.vQCEStoOUT [sCE,sTE,sYear,sSeason,sDay,sHour] for (_,sCE) in m.sQCEStoOUT_indexed[sTE]))) + #GWh + d['EQ_TELoss'] = Constraint(m.sTE,m.sTime, rule = EQ_TELoss, doc = 'TE losses for transportation processes [GWh]') + + + # Supply Technologies (ST)-related constraints + + + def EQ_STBalanceTE_Tra (m, sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Tra,sES_Tra,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Tra,sES_Tra]) == m.vQSTOut [sST_Tra,sES_Tra,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Tra'] = Constraint(m.sQSTOUT_Tra,m.sVinTime, rule = EQ_STBalanceTE_Tra, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Oth (m, sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour ): + return sum((m.vQSTInTE [sTE,sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Oth,sES_Oth,sTE,sVin]) for (_,_,sTE) in m.sQTESTES_STES_indexed[sST_Oth,sES_Oth]) == m.vQSTOut [sST_Oth,sES_Oth,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Oth'] = Constraint(m.sQSTOUT_Oth,m.sVinTime, rule = EQ_STBalanceTE_Oth, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STBalanceTE_Ind (m, sTE, sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInTE [sTE,sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] / m.pSTEffTE[sST_Ind,sES_Ind,sTE,sVin] == m.vQSTOut [sST_Ind,sES_Ind,sVin,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_STBalanceTE_Ind'] = Constraint(m.sQTESTES_Ind,m.sVinTime, rule = EQ_STBalanceTE_Ind, doc = 'Balance for ST consumption of TE [ES units]') + + + def EQ_STOutShareMin (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.pSTOutShareMin [sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) + #GWh + d['EQ_STOutShareMin'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMin, doc = 'Minimum ST output shares restriction [ES units]') + + + def EQ_STOutShareMax (m, sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.pSTOutShareMax[sST,sES] * sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_indexed[sST]) >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] + #GWh + d['EQ_STOutShareMax'] = Constraint(m.sQSTOUT,m.sVinTime, rule = EQ_STOutShareMax, doc = 'Maximum ES output shares restriction [ES units]') + + + # Transport modal shift constraints + + + #MINIMUM MODAL SHARE + + + def EQ_MinMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) >= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MinMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MinMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) >= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MinMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MinMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) >= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MinMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MinMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) >= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MinMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MinMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) >= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MinMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MinMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) >= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MinMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MinMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MinMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) - 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) >= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MinMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MinMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + #MAXIMUM MODAL SHARE + + def EQ_MaxMS_Car (m, sSD_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Car,sES_Tra,sYear] * m.pAFTra[sST_Tra_Car,sES_Tra,sSD_Tra_Car]) for (_,sES_Tra,sST_Tra_Car) in m.sQSTOUT_AFTraCar_indexed[sSD_Tra_Car])/sum(m.pDC[sSD_Tra_Car,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Car])) <= 1e4*m.pSTTra_MS['Car',sSD_Tra_Car] + #GWh + d['EQ_MaxMS_Car'] = Constraint(m.sSD_Tra_Car, m.sYear, rule = EQ_MaxMS_Car, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Bus (m, sSD_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*( (sum((m.vQES[sST_Tra_Bus,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Bus,sES_Tra,sYear] * m.pAFTra[sST_Tra_Bus,sES_Tra,sSD_Tra_Bus]) for (_,sES_Tra,sST_Tra_Bus) in m.sQSTOUT_AFTraBus_indexed[sSD_Tra_Bus])/sum(m.pDC[sSD_Tra_Bus,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Bus])) <= 1e4*m.pSTTra_MS['Bus',sSD_Tra_Bus] + #GWh + d['EQ_MaxMS_Bus'] = Constraint(m.sSD_Tra_Bus, m.sYear, rule = EQ_MaxMS_Bus, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Moped (m, sSD_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*((sum((m.vQES[sST_Tra_Moped,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Moped,sES_Tra,sYear] * m.pAFTra[sST_Tra_Moped,sES_Tra,sSD_Tra_Moped]) for (_,sES_Tra,sST_Tra_Moped) in m.sQSTOUT_AFTraMoped_indexed[sSD_Tra_Moped])/sum(m.pDC[sSD_Tra_Moped,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Moped])) <= 1e4*m.pSTTra_MS['Moped',sSD_Tra_Moped] + #GWh + d['EQ_MaxMS_Moped'] = Constraint(m.sSD_Tra_Moped, m.sYear, rule = EQ_MaxMS_Moped, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_IntRail (m, sSD_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*( (sum((m.vQES[sST_Tra_IntRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_IntRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_IntRail,sES_Tra,sSD_Tra_IntRail]) for (_,sES_Tra,sST_Tra_IntRail) in m.sQSTOUT_AFTraIntRail_indexed[sSD_Tra_IntRail])/sum(m.pDC[sSD_Tra_IntRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_IntRail])) <= 1e4*m.pSTTra_MS['IntRail',sSD_Tra_IntRail] + #GWh + d['EQ_MaxMS_IntRail'] = Constraint(m.sSD_Tra_IntRail, m.sYear, rule = EQ_MaxMS_IntRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_UrbanRail (m, sSD_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*( (sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_UrbanRail,sES_Tra,sYear] * m.pAFTra[sST_Tra_UrbanRail,sES_Tra,sSD_Tra_UrbanRail]) for (_,sES_Tra,sST_Tra_UrbanRail) in m.sQSTOUT_AFTraUrbRail_indexed[sSD_Tra_UrbanRail])/sum(m.pDC[sSD_Tra_UrbanRail,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_UrbanRail])) <= 1e4*m.pSTTra_MS['UrbanRail',sSD_Tra_UrbanRail] + #GWh + d['EQ_MaxMS_UrbanRail'] = Constraint(m.sSD_Tra_UrbanRail, m.sYear, rule = EQ_MaxMS_UrbanRail, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Air (m, sSD_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*( (sum((m.vQES[sST_Tra_Air,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Air,sES_Tra,sYear] * m.pAFTra[sST_Tra_Air,sES_Tra,sSD_Tra_Air]) for (_,sES_Tra,sST_Tra_Air) in m.sQSTOUT_AFTraAir_indexed[sSD_Tra_Air])/sum(m.pDC[sSD_Tra_Air,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Air])) <= 1e4*m.pSTTra_MS['Air',sSD_Tra_Air] + #GWh + d['EQ_MaxMS_Air'] = Constraint(m.sSD_Tra_Air, m.sYear, rule = EQ_MaxMS_Air, doc = 'Minimum ST output shares restriction [ES units]') + + def EQ_MaxMS_Sea (m, sSD_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*( (sum((m.vQES[sST_Tra_Sea,sES_Tra,m.sYear.prev(sYear)] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,m.sYear.prev(sYear)] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea]))) + 1e4*m.pMSMax + else: + return 1e4*(sum((m.vQES[sST_Tra_Sea,sES_Tra,sYear] * m.pAFTra[sST_Tra_Sea,sES_Tra,sSD_Tra_Sea]) for (_,sES_Tra,sST_Tra_Sea) in m.sQSTOUT_AFTraSea_indexed[sSD_Tra_Sea])/sum(m.pDC[sSD_Tra_Sea,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra_Sea])) <= 1e4*m.pSTTra_MS['Sea',sSD_Tra_Sea] + #GWh + d['EQ_MaxMS_Sea'] = Constraint(m.sSD_Tra_Sea, m.sYear, rule = EQ_MaxMS_Sea, doc = 'Minimum ST output shares restriction [ES units]') + + + + def EQ_TC_Car (m, sST_Tra_Car,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Car,sVin,m.sYear.prev(sYear)] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Car,sYear] <= sum(m.pSTInsCap [sST_Tra_Car,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Car,sVin] for (sST_Tra_Car,sVin) in m.sST_Tra_Car*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Car'] = Constraint(m.sST_Tra_Car, m.sYear, rule = EQ_TC_Car, doc = '[ST units]') + + + def EQ_TC_Moped (m, sST_Tra_Moped,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Moped,sVin,m.sYear.prev(sYear)] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Moped,sYear] <= sum(m.pSTInsCap [sST_Tra_Moped,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Moped,sVin] for (sST_Tra_Moped,sVin) in m.sST_Tra_Moped*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Moped'] = Constraint(m.sST_Tra_Moped, m.sYear, rule = EQ_TC_Moped, doc = '[ST units]') + + + def EQ_TC_RoadFreight (m, sST_Tra_RoadFreight,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_RoadFreight,sVin,m.sYear.prev(sYear)] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_RoadFreight,sYear] <= sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_RoadFreight,sVin] for (sST_Tra_RoadFreight,sVin) in m.sST_Tra_RoadFreight*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_RoadFreight'] = Constraint(m.sST_Tra_RoadFreight, m.sYear,rule = EQ_TC_RoadFreight, doc = '[ST units]') + + + def EQ_TC_Bus (m, sST_Tra_Bus,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Bus,sVin,m.sYear.prev(sYear)] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Bus,sYear] <= sum(m.pSTInsCap [sST_Tra_Bus,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Bus,sVin] for (sST_Tra_Bus,sVin) in m.sST_Tra_Bus*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Bus'] = Constraint(m.sST_Tra_Bus, m.sYear, rule = EQ_TC_Bus, doc = '[ST units]') + + + def EQ_TC_UrbanRail (m, sST_Tra_UrbanRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_UrbanRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_UrbanRail,sYear] <= sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_UrbanRail,sVin] for (sST_Tra_UrbanRail,sVin) in m.sST_Tra_UrbanRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_UrbanRail'] = Constraint(m.sST_Tra_UrbanRail, m.sYear, rule = EQ_TC_UrbanRail, doc = '[ST units]') + + + def EQ_TC_IntRail (m, sST_Tra_IntRail,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_IntRail,sVin,m.sYear.prev(sYear)] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_IntRail,sYear] <= sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_IntRail,sVin] for (sST_Tra_IntRail,sVin) in m.sST_Tra_IntRail*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_IntRail'] = Constraint(m.sST_Tra_IntRail, m.sYear, rule = EQ_TC_IntRail, doc = '[ST units]') + + + def EQ_TC_Air (m, sST_Tra_Air,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Air,sVin,m.sYear.prev(sYear)] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Air,sYear] <= sum(m.pSTInsCap [sST_Tra_Air,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Air,sVin] for (sST_Tra_Air,sVin) in m.sST_Tra_Air*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Air'] = Constraint(m.sST_Tra_Air, m.sYear, rule = EQ_TC_Air, doc = '[ST units]') + + + def EQ_TC_Sea (m, sST_Tra_Sea,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Tra_Sea,sVin,m.sYear.prev(sYear)] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Tra_Sea,sYear] <= sum(m.pSTInsCap [sST_Tra_Sea,sVin] for sVin in m.sVin if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Tra_Sea,sVin] for (sST_Tra_Sea,sVin) in m.sST_Tra_Sea*m.sVin if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Sea'] = Constraint(m.sST_Tra_Sea, m.sYear, rule = EQ_TC_Sea, doc = '[ST units]') + + + + def EQ_TC_Oth (m, sST_Oth,sES_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + m.pTCMax * sum(m.vSTTotCap [sST_Oth,sVin,m.sYear.prev(sYear)] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin,m.sYear.prev(sYear)) in m.sVinYear) + else: + return m.vSTNewCap [sST_Oth,sYear] <= sum(m.pSTInsCap [sST_Oth,sVin] for sVin in m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + m.pTCMax * sum(m.pSTInsCap [sST_Oth,sVin] for (sST_Oth,sVin) in m.sST_Oth*m.sVin if (sST_Oth,sES_Oth) in m.sQSTOUT_Oth if (sVin, sYear) in m.sVinYear) + #GWh + d['EQ_TC_Oth'] = Constraint(m.sQSTOUT_Oth, m.sYear, rule = EQ_TC_Oth, doc = '[ST units]') + + + # Energy Services (ES)-related constraints + + + def EQ_ESBalance (m,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sVin) in m.sVinYear_indexed[sYear]) >= m.vQES [sST,sES,sYear] * m.pESLoad[sES,sSeason,sDay,sHour] #- m.vQESNS [sST,sES,sYear,sSeason,sDay,sHour] + #ES units + d['EQ_ESBalance'] = Constraint(m.sQSTOUT,m.sTime, rule = EQ_ESBalance, doc = 'Balance for ES [ES units]') + + + # Demand-related constraints + + + #Industry + + ##RM consumption + def EQ_STBalanceRM (m,sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour ): + return m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] >= m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] * m.pSTEffRM[sRM,sST,sES] + #ES units + d['EQ_STBalanceRM'] = Constraint(m.sQSTInRM,m.sVinTime, rule = EQ_STBalanceRM, doc = 'Balance for ST consumption of RM [RM units]') + + + ##AF + def EQ_AFInd (m,sSD_Ind,sYear ): + return sum((m.vQES [sST_Ind,sES_Ind,sYear] * m.pAFInd[sES_Ind,sSD_Ind]) for (_,sES_Ind,sST_Ind) in m.sQSTOUT_AFInd_indexed[sSD_Ind]) >= m.vQSDInd[sSD_Ind,sYear] + #Mt + d['EQ_AFInd'] = Constraint(m.sSD_Ind,m.sYear, rule = EQ_AFInd, doc = 'Activity Factor Industry [SD units]') + + + ##DC + def EQ_DCInd (m,sMD_Ind,sYear ): + return sum((m.vQSDInd[sSD_Ind,sYear] * m.pDC[sSD_Ind,sMD_Ind]) for sSD_Ind in m.sSD_Ind if ((sSD_Ind,sMD_Ind) in m.sQSDMD)) >= m.pMD[sMD_Ind,sYear] + #Mt + d['EQ_DCInd'] = Constraint(m.sMD_Ind,m.sYear, rule = EQ_DCInd, doc = 'Demand characterization Industry [MD units]') + + + ## Circularity constraint + def EQ_CircularityInd (m,sRM,sST,sES,sYear,sSeason,sDay,sHour ): + return sum(m.vQSTOut [sST,sES,sVin,sYear,sSeason,sDay,sHour] for (sST,sVin) in m.sST_Ind*m.sVin if ((sST,sES) in m.sQSTOUT_Ind and (sVin,sYear) in m.sVinYear)) >= sum(m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) / m.pRMCircular[sES,sRM] + #Mt + d['EQ_CircularityInd'] = Constraint(m.sQSTInRM_Cir,m.sTime, rule = EQ_CircularityInd, doc = 'Circularity constraintis [RM units]') + + + + # Endogenous behavioural measures + + + #Transportation + + ##AF + def EQ_AFTra (m,sSD_Tra,sYear ): + return sum((m.vQES[sST_Tra,sES_Tra,sYear] * m.pAFTra[sST_Tra,sES_Tra,sSD_Tra]) for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) + sum( sum(m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] for (_,sES_Tra,sST_Tra) in m.sQSTOUT_AFTra_indexed[sSD_Tra]) for sBM_Tra in m.sBM_Tra) >= m.vQSDTra [sSD_Tra,sYear] + # SD units (Mpkm) + d['EQ_AFTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_AFTra, doc = 'Activity factor Transportation [SD units]') + + + + ##BM + def EQ_BMTra (m,sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear ): + return m.vBMTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra,sYear] <= m.pDeltaAFTra[sST_Tra,sES_Tra,sSD_Tra,sBM_Tra] * m.vQES[sST_Tra,sES_Tra,sYear] + # SD units (Mpkm) + d['EQ_BMTra'] = Constraint(m.sQSTESSD_Tra,m.sBM_Tra,m.sYear, rule = EQ_BMTra, doc = 'Behavioural Measures in Transportation [ES units]') + + + + ##DC + def EQ_DCTra (m,sSD_Tra,sYear ): + return m.vQSDTra [sSD_Tra,sYear] >= sum(m.pDC[sSD_Tra,sMD_Tra] * m.pMD[sMD_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) - sum(sum(m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] for (_,sMD_Tra) in m.sQSDMD_Tra_indexed[sSD_Tra]) for sDM_Tra in m.sDM_Tra) + # SD units + d['EQ_DCTra'] = Constraint(m.sSD_Tra,m.sYear, rule = EQ_DCTra, doc = 'Demand characterization Transportation [SD units]') + + + + ##DM + def EQ_DMTra (m,sSD_Tra,sMD_Tra,sDM_Tra,sYear ): + return m.vDMTra[sSD_Tra,sMD_Tra,sDM_Tra,sYear] <= m.pDeltaDC[sSD_Tra,sMD_Tra,sDM_Tra] * m.pMD[sMD_Tra,sYear] + # + d['EQ_DMTra'] = Constraint(m.sQSDMD_Tra,m.sDM_Tra,m.sYear, rule = EQ_DMTra, doc = 'Demand shift Measures in Transportation [MD units]') + + + + #Others + + ##AF + def EQ_AFOth (m,sES_Oth,sYear ): + return (sum((m.vQES [sST_Oth,sES_Oth,sYear]) for (_,sST_Oth) in m.sQSTOUT_AFOth_indexed[sES_Oth]) + >= sum((m.vQSDOth [sSD_Oth,sMD_Oth,sYear] * m.pAFOth[sES_Oth,sSD_Oth,sMD_Oth]) for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed [sES_Oth]) + - sum(sum(m.vBMOth [sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth]) for sBM_Oth in m.sBM_Oth) + + sum(sum(m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for ( sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_WAMAC') + + sum(sum(m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] for (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) for sBM_Oth in m.sBM_Oth if sES_Oth == 'sES_DSOTH_RES_DIWAC') + + sum(m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth, sYear] for (_,sSD_Oth,sMD_Oth) in m.sQSDMD_Oth_indexed[sES_Oth])) + # ES units + d['EQ_AFOth'] = Constraint(m.sES_Oth,m.sYear, rule = EQ_AFOth, doc = 'Activity factor Others [ES units]') + + + + ##BM + def EQ_BMOth (m,sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth,sYear] <= m.pDeltaAFOth[sES_Oth,sSD_Oth,sMD_Oth,sBM_Oth] * m.vQSDOth [sSD_Oth,sMD_Oth,sYear] + # SD units () + d['EQ_BMOth'] = Constraint(m.sQESSDMD_Oth,m.sBM_Oth,m.sYear, rule = EQ_BMOth, doc = 'Behavioural Measures in Others [SD units]') + + + ##BM + def EQ_BMOth_WAMA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_WAMAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_WAMAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_WAMA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_WAMA, doc = 'Behavioural Measures in Others. Washing Machines [SD units]') + + + ##BM + def EQ_BMOth_DIWA (m,sSD_Oth,sMD_Oth,sBM_Oth,sYear ): + return m.vBMOth['sES_DSOTH_RES_DIWAH',sSD_Oth,sMD_Oth,sBM_Oth,sYear] == - m.vBMOth_DIWAC [sSD_Oth,sMD_Oth,sBM_Oth,sYear] + # SD units () + d['EQ_BMOth_DIWA'] = Constraint(m.sQSDMD_Res,m.sBM_Oth,m.sYear, rule = EQ_BMOth_DIWA, doc = 'Behavioural Measures in Others. Dish Washers [SD units]') + + + ##BM + def EQ_BMOth_TW (m,sES_Oth,sSD_Oth,sMD_Oth,sYear ): + return m.vBMOth_TW[sES_Oth,sSD_Oth,sMD_Oth,sYear] == m.pTW [sES_Oth,sSD_Oth,sMD_Oth] * sum(m.vDMTra[sSD_Tra,sMD_Tra,'sDM_Tra_TW',sYear] for (sSD_Tra,sMD_Tra) in m.sQSDMD_Tra) + # SD units () + d['EQ_BMOth_TW'] = Constraint(m.sQESSDMD_Oth,m.sYear, rule = EQ_BMOth_TW, doc = 'Behavioural Measures in Others. Telework [SD units]') + + + + #DC + def EQ_DCOth (m,sSD_Oth,sMD_Oth,sYear ): + return m.vQSDOth [sSD_Oth,sMD_Oth,sYear] >= m.pDC[sSD_Oth,sMD_Oth] * m.pMD[sMD_Oth,sYear] + (sum(m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_HE) - sum(m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] for sDM_Oth in m.sDM_Oth if sSD_Oth in m.sSD_Oth_LE)) + # SD units: MDwellings or km2 + d['EQ_DCOth'] = Constraint(m.sQSDMD_Oth,m.sYear, rule = EQ_DCOth, doc = 'Demand characterization Others [SD units]') + + + + ##DM + def EQ_DMOth (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] <= sum(m.pDeltaDC[sSD_Oth,sMD_Oth,sDM_Oth] * m.pMD[sMD_Oth,sYear] for sSD_Oth in m.sSD_Oth_HE if (sSD_Oth,sMD_Oth) in m.sQSDMD_Oth) + # + d['EQ_DMOth'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth2 (m,sMD_Oth,sDM_Oth,sYear ): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] == m.vDMOth_LE[sMD_Oth,sDM_Oth,sYear] + # + d['EQ_DMOth2'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth2, doc = 'Demand shift Measures in Others [SD units]') + + + + ##DM + def EQ_DMOth3 (m,sMD_Oth,sDM_Oth,sYear ): + if sYear>m.sYear.first(): + return m.vDMOth_HE[sMD_Oth,sDM_Oth,sYear] >= m.vDMOth_HE[sMD_Oth,sDM_Oth,m.sYear.prev(sYear)] + else: + return Constraint.Skip + # + d['EQ_DMOth3'] = Constraint(m.sMD_Oth,m.sDM_Oth,m.sYear, rule = EQ_DMOth3, doc = 'Demand shift Measures in Others [SD units]') + + + # Conversion Energy (CE) capacity constraints + + + def EQ_CEMaxPro_Pri (m, sCEPri,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCEPri,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCEPri,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCEPri,sYear,sSeason,sDay,sHour] if sCEPri in m.sCE_Ele else 0) + sum(m.vQCEPriOUT [sCEPri,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEPriOUT_CE_indexed[sCEPri]) + #GWh + d['EQ_CEMaxPro_Pri'] = Constraint(m.sCEPri,m.sTime, rule = EQ_CEMaxPro_Pri, doc = 'CE maximum production (sCEPri) [GWh]') + + + def EQ_CEMaxPro_Sec (m, sCESec,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESec,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESec,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESec,sYear,sSeason,sDay,sHour] if sCESec in m.sCE_Ele else 0) + sum(m.vQCESecOUT [sCESec,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCESecOUT_CE_indexed[sCESec]) + #GWh + d['EQ_CEMaxPro_Sec'] = Constraint(m.sCESec,m.sTime, rule = EQ_CEMaxPro_Sec, doc = 'CE maximum production (sCESec) [GWh]') + + + def EQ_CEMaxPro_Sto (m, sCESto,sYear,sSeason,sDay,sHour ): + return m.vCEActCap [sCESto,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] * m.pCEAF [sCESto,sSeason,sDay,sHour] >= (m.vCEEleReserv [sCESto,sYear,sSeason,sDay,sHour] if sCESto in m.sCE_Ele else 0) + sum(m.vQCEStoOUT [sCESto,sTE,sYear,sSeason,sDay,sHour] for (_,sTE) in m.sQCEStoOUT_CE_indexed[sCESto]) + #GWh + d['EQ_CEMaxPro_Sto'] = Constraint(m.sCESto,m.sTime, rule = EQ_CEMaxPro_Sto, doc = 'CE maximum production (sCESto) [GWh]') + + + def EQ_CEMaxCap (m, sCE,sYear ): + return m.pCEMaxCap [sCE] >= m.vCETotCap [sCE,sYear] + #GW + d['EQ_CEMaxCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEMaxCap, doc = 'CE maximum capacity [GW]') + + + def EQ_CEInsCap (m, sCE,sYear ): + return m.vCETotCap [sCE,sYear] == (m.vCETotCap[sCE,m.sYear.prev(sYear)] if sYear>m.sYear.first() else ((1-m.pGreenfield) * m.pCEInsCap[sCE])) + (m.vCENewCap [sCE,sYear]) - (m.vCEDecCap [sCE,sYear]) + #GW + d['EQ_CEInsCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEInsCap, doc = 'CE installed capacity [GW]') + + + def EQ_CEDecCap (m, sCE,sYear ): + return m.vCEDecCap [sCE,sYear] == ( + ((1-m.pGreenfield) * m.pYrGap * (m.pCEInsCap[sCE]/m.pCELife[sCE]) if ((m.sYear.ord(sYear) <= (m.pCELife[sCE]/m.pYrGap)) and (not sCE in (m.sCE_Hydro))) else 0) + + (m.vCENewCap[sCE,m.sYear.prev(sYear, m.pCELife[sCE]//int(m.pYrGap))] if m.sYear.ord(sYear) > (m.pCELife[sCE]/m.pYrGap) else 0) + ) + #GW + d['EQ_CEDecCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEDecCap, doc = 'CE decommissioned capacity [GW]') + + + def EQ_CEActCap (m, sCE,sYear ): + return m.vCEActCap [sCE,sYear] == m.vCETotCap [sCE,sYear] - m.vCEHibCap [sCE, sYear] + #GW + d['EQ_CEActCap'] = Constraint(m.sCE,m.sYear, rule = EQ_CEActCap, doc = 'CE active capacity [GW]') + + + def EQ_CEReactCap (m, sCE,sYear ): + return m.vCEDeltaActCap [sCE,sYear] >= - m.vCEHibCap [sCE, sYear] + (m.vCEHibCap [sCE, m.sYear.prev(sYear)] if (not sYear==m.sYear.first()) else 0) - m.vCEDecCap[sCE,sYear] + #GW + d['EQ_CEReactCap'] = Constraint(m.sCE, m.sYear, rule = EQ_CEReactCap, doc = 'Reactivation of CE capacity [GW]') + + + + def EQ_CEEleReserv (m, sYear,sSeason,sDay,sHour ): + return sum(m.vCEEleReserv [sCE_Ele,sYear,sSeason,sDay,sHour] * m.pCEFlex [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= ( m.pCEFailCap + + sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) * m.pCEDemErr + + sum( m.vCEActCap[sCE_Var,sYear] * m.pCEAF [sCE_Var,sSeason,sDay,sHour] for sCE_Var in m.sCE_Var) * m.pCEAFErr + ) + #GW + d['EQ_CEEleReserv'] = Constraint(m.sTime, rule = EQ_CEEleReserv, doc = 'Reserves for electricity generation [GW]') + + + + def EQ_EleMaxDem (m, sYear,sSeason,sDay,sHour ): + return m.vEleMaxDem [sYear] >= sum((m.vQSTInTE [sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour]/(m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour])) for (_,_,_,_,sTE,sST,sES,sVin) in m.sTESTESVinTime_Ele_indexed[sYear,sSeason,sDay,sHour]) + #GW + d['EQ_EleMaxDem'] = Constraint(m.sTime, rule = EQ_EleMaxDem, doc = 'Yearly maximum electricity power demand [GW]') + + + + def EQ_CEEleAdeq (m, sYear ): + return sum(m.vCEActCap [sCE_Ele,sYear] * m.pCEFirm [sCE_Ele] for sCE_Ele in m.sCE_Ele) >= (1 + m.pCEResMar) * m.vEleMaxDem [sYear] + #GW + d['EQ_CEEleAdeq'] = Constraint(m.sYear, rule = EQ_CEEleAdeq, doc = 'Adequacy for electricity generation [GW]') + + + def EQ_NucCap (m, sCE_Nuc,sYear ): + return (m.pCEInsCap[sCE_Nuc] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Nuc,sYear] + #GW + d['EQ_NucCap'] = Constraint(m.sCE_Nuc,m.sYear, rule = EQ_NucCap, doc = 'Nuclear dismantling restriction [GW]') + + + def EQ_CoalCap (m, sCE_Coal,sYear ): + return (m.pCEInsCap[sCE_Coal] if m.sYear.ord(sYear)= m.vCEActCap[sCE_Coal,sYear] + #GW + d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + + + # Supply Technologies (ST) capacity constraints + + + def EQ_STMaxProCap (m, sST_Cap,sVin,sYear,sSeason,sDay,sHour ): + return m.vSTTotCap [sST_Cap,sVin,sYear] * m.pNumHours * m.pTimeSlice [sSeason,sDay,sHour] >= sum(m.vQSTOut [sST_Cap,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES) in m.sQSTOUT_sST_Cap[sST_Cap]) + #GWh + d['EQ_STMaxProCap'] = Constraint(m.sST_Cap,m.sVinTime, rule = EQ_STMaxProCap, doc = 'ST maximum production [ES units]') + + + def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): + return m.vSTTotCap [sST_Uni,sVin,sYear] * m.pSTMaxPro[sST_Uni] >= sum(m.vQSTOut [sST_Uni,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sES,sSeason,sDay,sHour) in m.sQSTOUT_sST_Uni[sST_Uni]) + #GWh + d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') + + + + #def EQ_STMaxCap (m, sST,sYear ): + # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + #GW + #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + + + + def EQ_STInsCap (m, sST,sVin,sYear ): + return m.vSTTotCap [sST,sVin,sYear] == ((1-m.pGreenfield) * m.pSTInsCap[sST,sVin] if sYear==m.sYear.first() else 0) + (m.vSTTotCap[sST,sVin,m.sYear.prev(sYear)] if (sYear>m.sYear.first() and m.pYr[sYear]>m.pYr[sVin]) else 0) + (m.vSTNewCap [sST,sYear] if m.pYr[sYear]==m.pYr[sVin] else 0) - (m.vSTDecCap [sST,sVin,sYear] if m.pYr[sYear]>m.pYr[sVin] else 0) + #GW + d['EQ_STInsCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STInsCap, doc = 'ST installed capacity [ST units]') + + + def EQ_STDecCap (m, sST,sVin, sYear ): + return m.vSTDecCap [ sST,sVin, sYear ] == ( + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + + #GW + d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') + + + # ### Emissions accounting + + # CO2 emissions + + + ##CE + + def EQ_EmiCO2CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiCO2CEPri[sPE,sCEPri,sYear] == m.pEmiCO2CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #ktCO2 + d['EQ_EmiCO2CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiCO2CEPri, doc = 'CO2 emissions in Primary CE processes [ktCO2]') + + + def EQ_EmiCO2CESec (m, sTE,sCESec,sYear ): + return m.vEmiCO2CESec[sTE,sCESec,sYear] == m.pEmiCO2CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #ktCO2 + d['EQ_EmiCO2CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiCO2CESec, doc = 'CO2 emissions in Secondary CE processes [ktCO2]') + + + def EQ_EmiCO2CESto (m, sTE,sCESto,sYear ): + return m.vEmiCO2CESto[sTE,sCESto,sYear] == m.pEmiCO2CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #ktCO2 + d['EQ_EmiCO2CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiCO2CESto, doc = 'CO2 emissions in Storage CE processes [ktCO2]') + + def EQ_EmiCO2CE (m, sCE,sYear ): + return m.vEmiCO2CE[sCE,sYear] == sum(m.vEmiCO2CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiCO2CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]) + #ktCO2 + d['EQ_EmiCO2CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiCO2CE, doc = 'CO2 emissions in CE processes [ktCO2]') + + + ##TE + + def EQ_EmiCO2TE (m, sTE,sYear ): + return m.vEmiCO2TE[sTE,sYear] == m.pEmiCO2TE[sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,sST,sES,sVin,sSeason,sDay,sHour) in m.sSTESVinTime_indexed[sTE,sYear]) + sum(m.vQTELoss[sTE,sYear,sSeason,sDay,sHour] for (sSeason,sDay,sHour) in m.sYearTime)) + #ktCO2 + d['EQ_EmiCO2TE'] = Constraint(m.sTE,m.sYear, rule = EQ_EmiCO2TE, doc = 'CO2 emissions in TE transportation [ktCO2]') + + ##ST + + + def EQ_EmiCO2STTE (m,sTE,sST,sES,sYear ): + return m.vEmiCO2STTE[sTE,sST,sES,sYear] == m.pEmiCO2STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #ktCO2 + d['EQ_EmiCO2STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiCO2STTE, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2STPro (m,sST,sES,sYear ): + return m.vEmiCO2STPro[sST,sES,sYear] == m.pEmiCO2STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear]))/1e3 + #ktCO2 + d['EQ_EmiCO2STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2STPro, doc = 'CO2 emissions in ST due to TE consumption [ktCO2]') + + + def EQ_EmiCO2ST (m, sST,sES,sYear ): + return m.vEmiCO2ST[sST,sES,sYear] == sum(m.vEmiCO2STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiCO2STPro[sST,sES,sYear] + #ktCO2 + d['EQ_EmiCO2ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiCO2ST, doc = 'CO2 emissions in ST [ktCO2]') + + ##ESNS + + def EQ_EmiCO2ESNS (m, sYear ): + return m.vEmiCO2ESNS [sYear] == m.pEmiCO2ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + #ktCO2 + d['EQ_EmiCO2ESNS'] = Constraint(m.sYear, rule = EQ_EmiCO2ESNS, doc = 'CO2 penalization emissions related to ENS (TE consumption and CE process) [ktCO2]') + + + ##Total + + def EQ_EmiCO2Tot (m, sYear ): + return m.vEmiCO2Tot [sYear] == (sum(m.vEmiCO2CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiCO2TE [sTE,sYear] for sTE in m.sTE) + sum(m.vEmiCO2ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT))/1e3 #+ m.vEmiCO2ESNS[sYear])/1e3 + #MtCO2 + d['EQ_EmiCO2Tot'] = Constraint(m.sYear, rule = EQ_EmiCO2Tot, doc = 'Total CO2 emissions [MtCO2]') + + + # NOx emissions + + + #NOx Emissions + + ##CE + + + def EQ_EmiNOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiNOxCEPri[sPE,sCEPri,sYear] == m.pEmiNOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tNOx + d['EQ_EmiNOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiNOxCEPri, doc = 'NOx emissions in Primary CE processes [tNOx]') + + + def EQ_EmiNOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiNOxCESec[sTE,sCESec,sYear] == m.pEmiNOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tNOx + d['EQ_EmiNOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiNOxCESec, doc = 'NOx emissions in Secondary CE processes [tNOx]') + + + def EQ_EmiNOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiNOxCESto[sTE,sCESto,sYear] == m.pEmiNOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tNOx + d['EQ_EmiNOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiNOxCESto, doc = 'NOx emissions in Storage CE processes [tNOx]') + + + def EQ_EmiNOxCE (m, sCE,sYear ): + return m.vEmiNOxCE[sCE,sYear] == (sum(m.vEmiNOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiNOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktNOx + d['EQ_EmiNOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiNOxCE, doc = 'NOx emissions in CE processes [tNOx]') + + + ##ST + + def EQ_EmiNOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiNOxSTTE[sTE,sST,sES,sYear] == m.pEmiNOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiNOxSTTE, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxSTPro (m,sST,sES,sYear ): + return m.vEmiNOxSTPro[sST,sES,sYear] == m.pEmiNOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tNOx + d['EQ_EmiNOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxSTPro, doc = 'NOx emissions in ST due to TE consumption [tNOx]') + + + def EQ_EmiNOxST (m, sST,sES,sYear ): + return m.vEmiNOxST[sST,sES,sYear] == (sum(m.vEmiNOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiNOxSTPro[sST,sES,sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiNOxST, doc = 'NOx emissions in ST [ktNOx]') + + + ##ESNS + + def EQ_EmiNOxESNS (m, sYear ): + return m.vEmiNOxESNS [sYear] == m.pEmiNOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktNOx + d['EQ_EmiNOxESNS'] = Constraint(m.sYear, rule = EQ_EmiNOxESNS, doc = 'NOx penalization emissions related to ENS (TE consumption and CE process) [ktNOx]') + + + ##Total + + def EQ_EmiNOxTot (m, sYear ): + return m.vEmiNOxTot [sYear] == (sum(m.vEmiNOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiNOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiNOxESNS[sYear])*1e-3 + #MtNOx + d['EQ_EmiNOxTot'] = Constraint(m.sYear, rule = EQ_EmiNOxTot, doc = 'Total NOx emissions [MtNOx]') + + + + # SOx emissions + + + ##CE + + def EQ_EmiSOxCEPri (m, sPE,sCEPri,sYear ): + return m.vEmiSOxCEPri[sPE,sCEPri,sYear] == m.pEmiSOxCEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tSOx + d['EQ_EmiSOxCEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiSOxCEPri, doc = 'SOx emissions in Primary CE processes [tSOx]') + + + def EQ_EmiSOxCESec (m, sTE,sCESec,sYear ): + return m.vEmiSOxCESec[sTE,sCESec,sYear] == m.pEmiSOxCESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tSOx + d['EQ_EmiSOxCESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiSOxCESec, doc = 'SOx emissions in Secondary CE processes [tSOx]') + + + def EQ_EmiSOxCESto (m, sTE,sCESto,sYear ): + return m.vEmiSOxCESto[sTE,sCESto,sYear] == m.pEmiSOxCESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tSOx + d['EQ_EmiSOxCESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiSOxCESto, doc = 'SOx emissions in Storage CE processes [tSOx]') + + def EQ_EmiSOxCE (m, sCE,sYear ): + return m.vEmiSOxCE[sCE,sYear] == (sum(m.vEmiSOxCEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiSOxCESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktSOx + d['EQ_EmiSOxCE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiSOxCE, doc = 'SOx emissions in CE processes [ktSOx]') + + + ##ST + + def EQ_EmiSOxSTTE (m,sTE,sST,sES,sYear ): + return m.vEmiSOxSTTE[sTE,sST,sES,sYear] == m.pEmiSOxSTTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiSOxSTTE, doc = 'SOx emissions in ST due to TE consumption [tSOx]') + + + def EQ_EmiSOxSTPro (m,sST,sES,sYear ): + return m.vEmiSOxSTPro[sST,sES,sYear] == m.pEmiSOxSTPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tSOx + d['EQ_EmiSOxSTPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxSTPro, doc = 'SOx emissions in ST due to TE consumption [kSOx]') + + + def EQ_EmiSOxST (m, sST,sES,sYear ): + return m.vEmiSOxST[sST,sES,sYear] == (sum(m.vEmiSOxSTTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiSOxSTPro[sST,sES,sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiSOxST, doc = 'SOx emissions in ST [ktSOx]') + + + ##ESNS + + def EQ_EmiSOxESNS (m, sYear ): + return m.vEmiSOxESNS [sYear] == m.pEmiSOxESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktSOx + d['EQ_EmiSOxESNS'] = Constraint(m.sYear, rule = EQ_EmiSOxESNS, doc = 'SOx penalization emissions related to ENS (TE consumption and CE process) [ktSOx]') + + + ##Total + + def EQ_EmiSOxTot (m, sYear ): + return m.vEmiSOxTot [sYear] == (sum(m.vEmiSOxCE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiSOxST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiSOxESNS[sYear])*1e-3 + #MtSOx + d['EQ_EmiSOxTot'] = Constraint(m.sYear, rule = EQ_EmiSOxTot, doc = 'Total SOx emissions [MtSOx]') + + + # PM 2.5 emissions + + + ##CE + + def EQ_EmiPM25CEPri (m, sPE,sCEPri,sYear ): + return m.vEmiPM25CEPri[sPE,sCEPri,sYear] == m.pEmiPM25CEPri[sPE,sCEPri] * sum(m.vQCEPriIN [sPE,sCEPri,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEPriIN_YTime_indexed[sPE,sCEPri,sYear]) + #tPM25 + d['EQ_EmiPM25CEPri'] = Constraint(m.sQCEPriIN,m.sYear, rule = EQ_EmiPM25CEPri, doc = 'PM25 emissions in Primary CE processes [tPM25]') + + + + def EQ_EmiPM25CESec (m, sTE,sCESec,sYear ): + return m.vEmiPM25CESec[sTE,sCESec,sYear] == m.pEmiPM25CESec[sTE,sCESec] * sum(m.vQCESecIN [sTE,sCESec,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCESecIN_YTime_indexed[sTE,sCESec,sYear]) + #tPM25 + d['EQ_EmiPM25CESec'] = Constraint(m.sQCESecIN,m.sYear, rule = EQ_EmiPM25CESec, doc = 'PM25 emissions in Secondary CE processes [tPM25]') + + + + def EQ_EmiPM25CESto (m, sTE,sCESto,sYear ): + return m.vEmiPM25CESto[sTE,sCESto,sYear] == m.pEmiPM25CESto[sTE,sCESto] * sum(m.vQCEStoIN[sTE,sCESto,sYear,sSeason,sDay,sHour] for (_,_,_,sSeason,sDay,sHour) in m.sQCEStoIN_YTime_indexed[sTE,sCESto,sYear]) + #tPM25 + d['EQ_EmiPM25CESto'] = Constraint(m.sQCEStoIN,m.sYear, rule = EQ_EmiPM25CESto, doc = 'PM25 emissions in Storage CE processes [tPM25]') + + def EQ_EmiPM25CE (m, sCE,sYear ): + return m.vEmiPM25CE[sCE,sYear] == (sum(m.vEmiPM25CEPri[sPE,sCE,sYear] for (_,sPE) in m.sQCEPriIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESec[sTE,sCE,sYear] for (_,sTE) in m.sQCESecIN_CE_indexed[sCE]) + sum(m.vEmiPM25CESto[sTE,sCE,sYear] for (_,sTE) in m.sQCEStoIN_CE_indexed[sCE]))*1e-3 + #ktPM25 + d['EQ_EmiPM25CE'] = Constraint(m.sCE,m.sYear, rule = EQ_EmiPM25CE, doc = 'PM25 emissions in CE processes [ktPM25]') + + + ##ST + + + def EQ_EmiPM25STTE (m,sTE,sST,sES,sYear ): + return m.vEmiPM25STTE[sTE,sST,sES,sYear] == m.pEmiPM25STTE[sST,sTE] * (sum(m.vQSTInTE[sTE,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,_,sVin,sSeason,sDay,sHour) in m.sSTESTESVinTime_indexed[sTE,sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STTE'] = Constraint(m.sQTESTES,m.sYear, rule = EQ_EmiPM25STTE, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25STPro (m,sST,sES,sYear ): + return m.vEmiPM25STPro[sST,sES,sYear] == m.pEmiPM25STPro[sST,sES] * (sum(m.vQSTOut[sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,_,_,sVin,sSeason,sDay,sHour) in m.sQSTOUT_ST_ES_Year_indexed[sST,sES,sYear])) + #tPM25 + d['EQ_EmiPM25STPro'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25STPro, doc = 'PM25 emissions in ST due to TE consumption [tPM25]') + + + def EQ_EmiPM25ST (m, sST,sES,sYear ): + return m.vEmiPM25ST[sST,sES,sYear] == (sum(m.vEmiPM25STTE[sTE,sST,sES,sYear] for (_,_,sTE) in m.sQTESTES_STES_indexed[sST,sES]) + m.vEmiPM25STPro[sST,sES,sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ST'] = Constraint(m.sQSTOUT,m.sYear, rule = EQ_EmiPM25ST, doc = 'PM25 emissions in ST [ktPM25]') + + + ##ESNS + + + def EQ_EmiPM25ESNS (m, sYear ): + return m.vEmiPM25ESNS [sYear] == m.pEmiPM25ESNS * sum(m.vQESNS[sST,sES,sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear])*1e-3 + #ktPM25 + d['EQ_EmiPM25ESNS'] = Constraint(m.sYear, rule = EQ_EmiPM25ESNS, doc = 'PM25 penalization emissions related to ENS (TE consumption and CE process) [ktPM25]') + + + ##Total + + + def EQ_EmiPM25Tot (m, sYear ): + return m.vEmiPM25Tot [sYear] == (sum(m.vEmiPM25CE [sCE,sYear] for sCE in m.sCE) + sum(m.vEmiPM25ST [sST,sES,sYear] for (sST,sES) in m.sQSTOUT) + m.vEmiPM25ESNS[sYear])*1e-3 + #MtPM25 + d['EQ_EmiPM25Tot'] = Constraint(m.sYear, rule = EQ_EmiPM25Tot, doc = 'Total PM25 emissions [MtPM25]') + + + # ### Emission limits + + + ##Cap + + def EQ_EmiCO2Cap (m, sYear ): + return m.pEmiCO2Cap [sYear] >= m.vEmiCO2Tot [sYear] - m.vEmiCO2CapExc [sYear] + #MtCO2 + d['EQ_EmiCO2Cap'] = Constraint(m.sYear, rule = EQ_EmiCO2Cap, doc = 'Emission cap restriction [MtCO2]') + + + def EQ_EmiNOxCap (m, sYear ): + return m.pEmiNOxCap [sYear] >= m.vEmiNOxTot [sYear] - m.vEmiNOxCapExc [sYear] + #MtNOx + d['EQ_EmiNOxCap'] = Constraint(m.sYear, rule = EQ_EmiNOxCap, doc = 'Emission cap restriction [MtNOx]') + + + def EQ_EmiSOxCap (m, sYear ): + return m.pEmiSOxCap [sYear] >= m.vEmiSOxTot [sYear] - m.vEmiSOxCapExc [sYear] + #MtSOx + d['EQ_EmiSOxCap'] = Constraint(m.sYear, rule = EQ_EmiSOxCap, doc = 'Emission cap restriction [MtSOx]') + + + def EQ_EmiPM25Cap (m, sYear ): + return m.pEmiPM25Cap [sYear] >= m.vEmiPM25Tot [sYear] - m.vEmiPM25CapExc [sYear] + #MtPM25 + d['EQ_EmiPM25Cap'] = Constraint(m.sYear, rule = EQ_EmiPM25Cap, doc = 'Emission cap restriction [MtPM25]') + + + + ##Carbon budget + + def EQ_EmiCO2Budget (m ): + return m.pEmiCO2Budget >= m.pYrGap * sum(m.vEmiCO2Tot[sYear] for sYear in m.sYear)- m.vEmiCO2BudgetExc + #MtCO2 + d['EQ_EmiCO2Budget'] = Constraint( rule = EQ_EmiCO2Budget, doc = 'Emission budget restriction for the Before Net-zero target year period [MtCO2]') + + + + + # CO2 sectorial emissions limits + + + ## Transport + def EQ_EmiCO2CapTra (m, sYear ): + return m.pEmiCO2CapTra [sYear] >= sum(m.vEmiCO2ST [sST_Tra,sES_Tra,sYear] for (sST_Tra,sES_Tra) in m.sQSTOUT_Tra)*1e-3 - m.vEmiCO2CapTraExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapTra'] = Constraint(m.sYear, rule = EQ_EmiCO2CapTra, doc = 'Transport emission cap restriction [MtCO2]') + + + + ## Electric generation + def EQ_EmiCO2CapEle (m, sYear ): + return m.pEmiCO2CapEle [sYear] >= sum(m.vEmiCO2CE [sCE_Ele,sYear] for sCE_Ele in m.sCE_Ele)*1e-3 - m.vEmiCO2CapEleExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapEle'] = Constraint(m.sYear, rule = EQ_EmiCO2CapEle, doc = 'Electricity generation emission cap restriction [MtCO2]') + + + ## Industrial sector (energy) + def EQ_EmiCO2CapIndTE (m, sYear ): + return m.pEmiCO2CapIndTE [sYear] >= sum(m.vEmiCO2STTE[sTE,sST_Ind,sES_Ind,sYear] for (sTE,sST_Ind,sES_Ind) in m.sQTESTES_Ind)*1e-3 - m.vEmiCO2CapIndTEExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndTE'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndTE, doc = 'Energy-related industrial emission cap restriction [MtCO2]') + + + + ## Industrial sector (process) + def EQ_EmiCO2CapIndPro (m, sYear ): + return m.pEmiCO2CapIndPro [sYear] >= sum(m.vEmiCO2STPro[sST_Ind,sES_Ind,sYear] for (sST_Ind,sES_Ind) in m.sQSTOUT_Ind)*1e-3 - m.vEmiCO2CapIndProExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapIndPro'] = Constraint(m.sYear, rule = EQ_EmiCO2CapIndPro, doc = 'Process-related industrial emission cap restriction [MtCO2]') + + + ## Residential and commercial + def EQ_EmiCO2CapOth (m, sYear ): + return m.pEmiCO2CapOth [sYear] >= sum(m.vEmiCO2ST [sST_Oth,sES_Oth,sYear] for (sST_Oth,sES_Oth) in m.sQSTOUT_Oth)*1e-3 - m.vEmiCO2CapOthExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapOth'] = Constraint(m.sYear, rule = EQ_EmiCO2CapOth, doc = 'Residential&Commercial emission cap restriction [MtCO2]') + + + ## Refine industry + def EQ_EmiCO2CapRef (m, sYear ): + return m.pEmiCO2CapRef [sYear] >= sum(m.vEmiCO2CE [sCE_Ref,sYear] for sCE_Ref in m.sCE_Ref)*1e-3 - m.vEmiCO2CapRefExc [sYear] + #MtCO2 + d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') + + l_eq = [ + 'EQ_TotalCost_Unc', + #'EQ_UncCost', + 'EQ_UncCost_Cher', + 'EQ_UncCost_Cher2', + 'EQ_InvCostCE_Unc', + 'EQ_OpCost_Unc', + 'EQ_FObj', + 'EQ_SysCost', + 'EQ_PenalCost', + #'EQ_TotalCost', + 'EQ_BMCost', + 'EQ_DMCost', + #'EQ_InvCostCE', + 'EQ_InvCostST', + #'EQ_OpCost', + 'EQ_OpVarom', + 'EQ_PEDomCap', + 'EQ_PEImpCap', + 'EQ_PEBalance', + 'EQ_CEPriBalance', + 'EQ_CEPriOutShareMin', + 'EQ_CEPriOutShareMax', + 'EQ_CESecBalance', + 'EQ_CESecOutShareMin', + 'EQ_CESecOutShareMax', + 'EQ_CEStoBalance', + 'EQ_CEStoLevel', + 'EQ_CEStoOutShareMin', + 'EQ_CEStoOutShareMax', + 'EQ_CEStoMaxSto', + 'EQ_TEBalance', + 'EQ_TELoss', + 'EQ_STBalanceTE_Tra', + 'EQ_STBalanceTE_Oth', + 'EQ_STBalanceTE_Ind', + 'EQ_STOutShareMin', + 'EQ_STOutShareMax', + 'EQ_MinMS_Car', + 'EQ_MinMS_Bus', + 'EQ_MinMS_Moped', + 'EQ_MinMS_IntRail', + 'EQ_MinMS_UrbanRail', + 'EQ_MinMS_Air', + 'EQ_MinMS_Sea', + 'EQ_MaxMS_Car', + 'EQ_MaxMS_Bus', + 'EQ_MaxMS_Moped', + 'EQ_MaxMS_IntRail', + 'EQ_MaxMS_UrbanRail', + 'EQ_MaxMS_Air', + 'EQ_MaxMS_Sea', + #'EQ_TC_Car', + #'EQ_TC_Moped', + #'EQ_TC_RoadFreight', + #'EQ_TC_Bus', + #'EQ_TC_UrbanRail', + #'EQ_TC_IntRail', + #'EQ_TC_Air', + #'EQ_TC_Sea', + #'EQ_TC_Oth', + 'EQ_ESBalance', + 'EQ_AFTra', + 'EQ_BMTra', + 'EQ_DCTra', + 'EQ_DMTra', + 'EQ_AFOth', + 'EQ_BMOth', + 'EQ_BMOth_WAMA', + 'EQ_BMOth_DIWA', + 'EQ_BMOth_TW', + 'EQ_DCOth', + 'EQ_DMOth', + 'EQ_DMOth2', + 'EQ_DMOth3', + 'EQ_STBalanceRM', + 'EQ_AFInd', + 'EQ_DCInd', + 'EQ_CircularityInd', + 'EQ_CEMaxPro_Pri', + 'EQ_CEMaxPro_Sec', + 'EQ_CEMaxPro_Sto', + 'EQ_CEMaxCap', + 'EQ_CEInsCap', + 'EQ_CEDecCap', + 'EQ_CEActCap', + 'EQ_CEReactCap', + 'EQ_CEEleReserv', + 'EQ_EleMaxDem', + 'EQ_CEEleAdeq', + 'EQ_NucCap', + 'EQ_CoalCap', + 'EQ_STMaxProCap', + 'EQ_STMaxProUni', + #'EQ_STMaxCap', + 'EQ_STInsCap', + 'EQ_STDecCap', + 'EQ_EmiCO2CEPri', + 'EQ_EmiCO2CESec', + 'EQ_EmiCO2CESto', + 'EQ_EmiCO2CE', + 'EQ_EmiCO2TE', + 'EQ_EmiCO2STTE', + 'EQ_EmiCO2STPro', + 'EQ_EmiCO2ST', + #'EQ_EmiCO2ESNS', + 'EQ_EmiCO2Tot', + #'EQ_EmiNOxCEPri', + #'EQ_EmiNOxCESec', + #'EQ_EmiNOxCESto', + #'EQ_EmiNOxCE', + #'EQ_EmiNOxSTTE', + #'EQ_EmiNOxSTPro', + #'EQ_EmiNOxST', + #'EQ_EmiNOxESNS', + #'EQ_EmiNOxTot', + #'EQ_EmiSOxCEPri', + #'EQ_EmiSOxCESec', + #'EQ_EmiSOxCESto', + #'EQ_EmiSOxCE', + #'EQ_EmiSOxSTTE', + #'EQ_EmiSOxSTPro', + #'EQ_EmiSOxST', + #'EQ_EmiSOxESNS', + #'EQ_EmiSOxTot', + #'EQ_EmiPM25CEPri', + #'EQ_EmiPM25CESec', + #'EQ_EmiPM25CESto', + #'EQ_EmiPM25CE', + #'EQ_EmiPM25STTE', + #'EQ_EmiPM25STPro', + #'EQ_EmiPM25ST', + #'EQ_EmiPM25ESNS', + #'EQ_EmiPM25Tot', + 'EQ_EmiCO2Cap', + #'EQ_EmiNOxCap', + #'EQ_EmiSOxCap', + #'EQ_EmiPM25Cap', + 'EQ_EmiCO2Budget', + 'EQ_EmiCO2CapTra', + 'EQ_EmiCO2CapEle', + 'EQ_EmiCO2CapIndTE', + 'EQ_EmiCO2CapIndPro', + 'EQ_EmiCO2CapOth', + 'EQ_EmiCO2CapRef', + ] + for eq in l_eq: + setattr(m, eq, d[eq]) + + return m diff --git a/scenarios_orig/Correl_0_5/src/openMASTER/output_data.py b/scenarios_orig/Correl_0_5/src/openMASTER/output_data.py new file mode 100644 index 0000000..eccdbb8 --- /dev/null +++ b/scenarios_orig/Correl_0_5/src/openMASTER/output_data.py @@ -0,0 +1,161 @@ +# Libraries +import pandas as pd +import math +from pyomo.environ import Var +import os + + +# ========= +# Functions +# ========= + +# def list_to_excel_table(data, index_dim, output_path, file_name, sheet_name): +# """ +# Converting a Dataframe containing a Output Variable from a Pyomo model into a +# more comprehensive Excel table. +# +# INPUTS +# ====== +# data: Pandas Dataframe. Table containing the output variable info +# index_dim: list. Desired dimensions for the data indexes: index_dim[0]: row index dimensions +# index_dim[1]: col index dimensions +# output_path: str. Path to the Output folder. +# file_name: str. Name of the Excel file to create or where to concatenate new sheets. +# sheet_name: str. Name of the Excel sheet name where to store the variable info. Usually corresponds to the name of the variable. +# concatenate_to_table: bool. If True, the results are concatenated to the Excel table indicated in the "output_path", +# but in a new Excel sheet named after the variable "name". +# +# """ +# # Set names of the Pyomo Variable +# set_names = list(data.columns)[:-1] +# # Sets belonging to the rows +# row_sets = [set_names[index] for index in range(index_dim[0])] +# # Sets belonging to the columns +# column_sets = [set_names[index+index_dim[0]] for index in range(index_dim[1])] +# if index_dim[0] == 0 and index_dim[1] == 0: +# pivoted = data.copy() +# else: +# # Creating a pivot table index by the row and column sets +# pivoted = pd.pivot_table(data, index=row_sets, columns=column_sets) +# pivoted.reset_index(inplace=True) +# +# ## Changing the name and position of the indexes +# if index_dim[0] > 0 and index_dim[1] > 0: +# # Column indexes +# col_index_tuple = pivoted.columns.names +# new_col_index_tuple = tuple([None]*len(col_index_tuple)) +# pivoted.columns.names = new_col_index_tuple +# # Row indexes +# for i in range(index_dim[0]): +# # Changing the value of the indexes +# pivoted.columns.values[i] = tuple([""]) + tuple([col_index_tuple[j+1] for j in range(index_dim[1]-1)]) + tuple([pivoted.columns[i][0] + " / " + col_index_tuple[index_dim[1]]]) +# # Chaging the name of the indexes +# pivoted.rename(columns = {pivoted.columns[i]: pivoted.columns.values[i]}, inplace=True) +# +# # Eliminating the index from the pivoted table +# pivoted.index = [""] * len(pivoted) +# pivoted.rename(columns={"index": ""}, inplace=True) +# +# # Excel File Path +# output_file_path = os.path.join(output_path, file_name) +# # Checking if the Excel file is already created +# if os.path.exists(output_file_path): +# with pd.ExcelWriter(output_file_path, mode='a', engine='openpyxl') as writer: +# pivoted.to_excel(writer, sheet_name=sheet_name) +# else: +# pivoted.to_excel(output_file_path, sheet_name=sheet_name) +#------ + + +def export_model_to_csv(path, output_path, sheetname, m_instance): + """ + Extracting the information for each Output Variable in a Pyomo model. + + INPUTS + ====== + path: str. Path of the Excel file containing the variable data. + output_path. Path to the output folder. + sheetname: str. Excel sheetname containing the name of the sets for each variable. + m_instance: Pyomo model instance. + + RETURNS + ======= + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the sets of each variable + d_vars_sets = {} + # Dictionary for storing the info of each variable + d_vars = {} + + # Loading variables info + df_vars = pd.read_excel(path, sheet_name=sheetname) + # Setting the first column (variable name) as index + df_vars.set_index(df_vars.columns[0], inplace=True) + + + # Extracting the sets from the Excel file + for index, row in df_vars.iterrows(): + col_values = list(row[[col for col in df_vars.columns if "DIM_" in col and "ROW" not in col and "COL" not in col]].values) + col_values = [value for value in col_values if not ((isinstance(value, float) and math.isnan(float(value))) or value.replace(" ","") == "")] + d_vars_sets[index] = col_values + + # Make the folder if does not exist + os.makedirs(output_path, exist_ok=True) + # Iterating all variables in the instance of the model + for v in m_instance.component_objects(Var): + if (v.name) in df_vars.index: + # Extracting variable values + x_vals = pd.Series(v.extract_values(), name=v.name) + # Converting the variable data to a dataframe + df = x_vals.to_frame() + # Variable index names + index_names = d_vars_sets[v.name] + if len(index_names) == 0: + df = df.reset_index(drop=True) + else: + df = df.reset_index() + df.columns = d_vars_sets[v.name] + [v.name] + # Updating the variables dictionary with the complete variable info + d_vars[v.name] = df + + # Exporting the variable info to csv + df.to_csv(output_path + "/" + v.name + ".csv", index=False) + + return d_vars + +#------ + + +def import_results_from_csv(path): + """ + Load all the csv files corresponding to Variable data, convert them to Pandas Dataframe + and store them in a Python dictionary. + + INPUT + ===== + path: str. Path of the folder containing the csv files. + + RETURN + ====== + d_vars: dict. Dictionary containing the values for each variable in the model. + {: dataframe} + """ + # Dictionary for storing the info of each variable + d_vars = {} + + # Extracting the filename of all the files in the folder and + # processing those that correspond to variables. + for dir in os.listdir(path): + # Checking if the file corresponds to a variable + if dir.startswith("v"): + # Extracting the name of the variable + var_name = dir.split(".")[0].strip() + # Converting the csv file to a Python Dataframe + df = pd.read_csv(path + "/" + dir) + # Storing the variable info in a Python dictionary + d_vars[var_name] = df + + return d_vars + + diff --git a/scenarios_orig/Correl_0_5/src/openMASTER/scenarios.py b/scenarios_orig/Correl_0_5/src/openMASTER/scenarios.py new file mode 100644 index 0000000..9bbf7f9 --- /dev/null +++ b/scenarios_orig/Correl_0_5/src/openMASTER/scenarios.py @@ -0,0 +1,82 @@ +"""Scenario management""" + +import os +import shutil +import time +from datetime import datetime + +from openMASTER.utils import copy_and_overwrite + + + + +# Output Index config file path +excel_path = "./data/input/openMASTER_Data.xlsm" +# Loading the Output Index config +index_config = pd.read_excel(excel_path, sheet_name="Output") + +# Scenarios file path +scenarios_path = "./.scenarios" + +# Data file path +data_path = "./data" + +# Source file path +src_path = "./src" + + + +# Loading the scenario name +index_config_columns = list(index_config.columns) # Loading all the colums from the "Output" sheet +scenario_column = index_config_columns.index("Scenario name:") + 1 # Finding the scenario name in the list of columns +scenario_name = index_config_columns[scenario_column] # Extracting the scenario name + +# Loading the scenario description +for row in index_config.index: + for col_idx, col in enumerate(index_config.columns[:-1]): + if "Scenario description" in str(index_config.at[row, col]): + next_column = index_config.columns[col_idx + 1 ] + scenario_desc = index_config.at [row, next_column] + +# Loading the actual timestamp +current_timestamp = datetime.now().strftime("%d_%m_%Y-%H_%M_%S") + +# Generatinf a Scenario ID +scenarioID = scenario_name+"_"+current_timestamp + +# Extracting the sceneario general information +scenario_info = {"ScenarioID": scenarioID , "Scenario name": scenario_name, "Scenario description": scenario_desc} +df_scenario_info = pd.DataFrame.from_dict(scenario_info, orient='index').transpose() + +# Creating a folder with the name of the scenario +scenario_folder = os.path.join(scenarios_path, scenarioID) # Path of the new scenario folder + +try: + # Try to create the folder for the new scenario + os.mkdir(scenario_folder) +except FileExistsError: + # If the folder already exists, print a warning message + print(f"The folder {scenario_folder} already exists in the specified path. Content may be overwritten.") + +# Copying the contents from the data folder to the scenario folder +copy_and_overwrite(data_path, scenario_folder) + +# Copying the contents from the srcfolder to the scenario folder +copy_and_overwrite(src_path, scenario_folder) + + + +# Scenario Index File Path +scenario_index_path = "./.scenarios/scenarios_index.csv" + +# Adding the new scenario to the index of scenarios +if os.path.exists(scenario_index_path): + + # If the file exists, load it into a DataFrame + df_scenario_index = pd.read_csv(scenario_index_path) + df_scenario_index = pd.concat([df_scenario_index, df_scenario_info], axis=0, ignore_index=True) +else: + # If the file doesn't exist, create a new DataFrame with the desired columns + df_scenario_index = df_scenario_info.copy() + +df_scenario_index.to_csv(scenario_index_path, index=False) diff --git a/scenarios_orig/Correl_0_5/src/openMASTER/utils.py b/scenarios_orig/Correl_0_5/src/openMASTER/utils.py new file mode 100644 index 0000000..5ed32ba --- /dev/null +++ b/scenarios_orig/Correl_0_5/src/openMASTER/utils.py @@ -0,0 +1,13 @@ +import os.path +import shutil + +def copy_and_overwrite(src, dst): + # Create the subdirectory in the destination folder + subdirectory = os.path.join(dst, os.path.basename(src)) + + # If the subdirectory already exists, remove it + if os.path.exists(subdirectory): + shutil.rmtree(subdirectory) + + # Copy the contents of the source folder into the subdirectory + shutil.copytree(src, subdirectory) diff --git a/src/openMASTER/Graphing_Tool/openMASTER.png b/src/openMASTER/Graphing_Tool/openMASTER.png index 187abdc..436ce91 100644 Binary files a/src/openMASTER/Graphing_Tool/openMASTER.png and b/src/openMASTER/Graphing_Tool/openMASTER.png differ diff --git a/src/openMASTER/Graphing_Tool/openMASTER_nobg.png b/src/openMASTER/Graphing_Tool/openMASTER_nobg.png index e54c671..2840568 100644 Binary files a/src/openMASTER/Graphing_Tool/openMASTER_nobg.png and b/src/openMASTER/Graphing_Tool/openMASTER_nobg.png differ diff --git a/src/openMASTER/loader.py b/src/openMASTER/loader.py index 70de7be..3c665df 100644 --- a/src/openMASTER/loader.py +++ b/src/openMASTER/loader.py @@ -419,7 +419,7 @@ def _excel_table_to_list(path, sheetname, index_dim): for i in range(len(col_index_values)): temp_values[col_index_names[i]] = col_index_values[i] # Añadimos el valor de los parámetros - temp_values[sheetname] = current_column_values.values + temp_values[sheetname] = current_column_values.values[:,0] # Rellenamos los valores de los parámetros vacíos con 0.0 temp_values[sheetname].fillna(0.0, inplace = True) # Concatenamos los datos obtenidos a la lista de datos final (data_list) diff --git a/src/openMASTER/model.py b/src/openMASTER/model.py index d5ab427..e548edc 100644 --- a/src/openMASTER/model.py +++ b/src/openMASTER/model.py @@ -14,8 +14,9 @@ def make_model(): m = AbstractModel('openMASTER') - m.sPE = Set ( doc = "Primary Energy Commodities" ) - m.sCE = Set ( doc = "Conversion Energy Technologies" ) + m.sUnc = Set ( doc = "Primary Energy Commodities & Conversion Energy Technologies") + m.sPE = Set (within=m.sUnc, doc = "Primary Energy Commodities" ) + m.sCE = Set (within=m.sUnc, doc = "Conversion Energy Technologies" ) m.sTE = Set ( doc = "Final Energy Commodities" ) m.sRM = Set ( doc = "Raw Materials Commodities" ) m.sST = Set ( doc = "Energy Service Supply Technologies" ) @@ -99,6 +100,11 @@ def make_model(): m.sYearANZ = Set (within=m.sVin, doc = "After Net-Zero emissions target year period" ) m.sYearCoal = Set (within=m.sVin, doc = "Coal phase-out target year period" ) m.sYearNuc = Set (within=m.sVin, doc = "Nuclear dismantling target year period" ) + + # Note that F > f1. + m.f = Set ( ordered=True, doc = 'number of uncert parameters' ) + m.f1 = Set (within=m.f, ordered=True, doc = 'PCA number of principal components' ) + m.fr = Set (within=m.f, ordered=True, doc = 'f elements for rest (from f1 to F)' ) #Relational sets m.sQCEPriIN = Set (within=m.sPE*m.sCEPri, doc = "Input PE to Primary CE" ) @@ -252,7 +258,24 @@ def make_model(): #ESNS m.pESNSCost = Param( doc = 'Energy service non supplied cost [M€ per ES unit ]') - + + #PCA parameters + m.pUnc = Param(m.sUnc,m.sYear, doc = 'PE Cost and CE Capex [€ per MWh] or [€ per kW]') + m.pNumPCA = Param( doc = 'number of PCA' ) + + m.pS = Param( m.sUnc, within=Reals, doc = '') + + m.pW_max = Param(m.f, within=Reals, doc = '') + m.pW_min = Param(m.f, within=Reals, doc = '') + + m.pAlpha_up = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pAlpha_do = Param(m.sUnc,m.f, within=Reals, doc = '') + m.pRest = Param(m.sUnc,m.f, within=Reals, doc = '') + + #RO parameter + m.pTau = Param( within=Reals, doc = '') + m.pDeltaUnc = Param(m.sUnc,m.sYear, within=Reals, doc = '') + #PE Primary Energy characterization m.pPECost = Param(m.sPE,m.sYear, doc = 'PE Cost [€ per MWh ]') m.pPEDomCap = Param(m.sPE, doc = 'PE domestic consumption capacity [GW ]') @@ -277,7 +300,9 @@ def make_model(): m.pCEAF = Param( m.sCE, m.sSeason,m.sDay,m.sHour,doc = 'Availability factor of CE [% ]') m.pCEFlex = Param( m.sCE_Ele, doc = 'Electricity generation technology flexibility factor [% ]') m.pCEFirm = Param( m.sCE_Ele, doc = 'Electricity generation technology firmness factor [% ]') - + m.pCEInsPathwayCap = Param( m.sCE, m.sYear, doc = 'Installed capacity of CE in the pathway [GW ]') + m.pCECapExcess = Param( doc = 'Excess capacity of CE in the pathway [GW ]') + #TE Transformed energy characterization m.pTELoss = Param(m.sTE, doc = 'TE transportation losses [% ]') @@ -299,7 +324,9 @@ def make_model(): m.pSTDecom = Param(m.sST,m.sYear, doc = 'ST Decommission cost [G€ per ST unit ]') m.pSTDecProb = Param(m.sST,m.sAge, doc = 'ST decommission probability [% ]') m.pSTFixom = Param(m.sST, doc = 'ST Fixom cost [k€ per ST unit ]') - m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pSTVarom = Param(m.sST,m.sES, doc = 'ST Varom cost [ € per ES unit ]') + m.pSTInsPathwayCap = Param(m.sST,m.sYear, doc = 'Installed capacity of ST in the pathway [ST units ]') + m.pSTCapExcess = Param( doc = 'Excess capacity of ST in the pathway [ST units ]') m.pESLoad = Param(m.sES,m.sSeason,m.sDay,m.sHour, doc = 'ES load curve [% ]') #Activity factors @@ -390,7 +417,7 @@ def make_model(): m.vCEActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Active CE capacity [GW ]") m.vCEHibCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CE capacity in hibernation [GW ]") m.vCEDeltaActCap = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Reactivation of CE inactive capacity [GW ]") - + m.vCECapExc = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "Excess of CE capacity regarding the pathway [GW ]") m.vCEEleReserv = Var ( m.sCE_Ele, m.sTime, within = NonNegativeReals, doc = "CE electricity reserves [GW ]") m.vEleMaxDem = Var ( m.sYear, within = NonNegativeReals, doc = "Yearly maximum electricity demand in a time slice [GW ]") @@ -399,7 +426,7 @@ def make_model(): m.vSTNewCap = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "ST new installed capacity [GW ]") m.vSTDecCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST decommissioned capacity [GW ]") m.vSTTotCap = Var ( m.sST, m.sVinYear, within = NonNegativeReals, doc = "ST accumulated installed capacity [GW ]") - + m.vSTCapExc = Var ( m.sST, m.sYear, within = NonNegativeReals, doc = "Excess of ST capacity regarding the pathway [GW ]") #CO2 Emission variables m.vEmiCO2CE = Var ( m.sCE, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in CE processes [ktCO2 ]") m.vEmiCO2CEPri = Var (m.sQCEPriIN, m.sYear, within = NonNegativeReals, doc = "CO2 emissions produced in Primary CE processes [ktCO2 ]") @@ -459,8 +486,14 @@ def make_model(): m.vEmiCO2CapOthExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Residential&Service sector (slack variable) [MtCO2 ]") m.vEmiCO2CapRefExc = Var ( m.sYear, within = NonNegativeReals, doc = "Excess of CO2 emissions regarding Carbon Cap in Refinery sector (slack variable) [MtCO2 ]") - - + #Correlation Uncertainty + m.vBeta = Var (m.f,m.sYear, within = NonNegativeReals, doc = "PCA beta (dual variable) ") + m.vUncCost = Var ( m.sYear, within = NonNegativeReals, doc = "Uncertain cost ") + + #RO Uncertainty + m.vW = Var ( within = NonNegativeReals, doc = "RO Additional variable W ") + m.vP = Var (m.sUnc,m.sYear, within = NonNegativeReals, doc = "RO Additional variable P ") + d = dict() # ### **Equations** @@ -471,8 +504,93 @@ def EQ_FObj (m ): return (m.vSysCost) d['EQ_FObj'] = Objective (sense = minimize, rule = EQ_FObj, doc = 'Total system cost minimization objective function') - # #### Constraints + ##### Constraints + + + + + # Uncertainty eqs + + + def EQ_TotalCost_Unc (m, sYear ): + return m.vTotalCost[sYear] == m.vUncCost[sYear] + (1e-3*m.vOpCost[sYear]) + sum(m.vInvCostCE[sCE,sYear] for sCE in m.sCE) + sum(m.vInvCostST[sST,sYear] for sST in m.sST) + #G€ + d['EQ_TotalCost_Unc'] = Constraint(m.sYear, rule = EQ_TotalCost_Unc, doc = 'Annual Total Cost = Total Investment Cost + Total Operation Cost [G€]') + + + + def EQ_UncCost (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost'] = Constraint(m.sYear, rule = EQ_UncCost, doc = 'Annual Total Operation Cost [M€]') + + + + def EQ_UncCost_Cher (m, sYear ): + return m.vUncCost[sYear] == (sum(m.vBeta[f,sYear] for f in m.f1) + + (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pS[sPE] + sum(m.pAlpha_do[sPE,f] for f in m.f1) + sum(m.pRest[sPE,f] for f in m.fr)) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pS[sCE] + sum(m.pAlpha_do[sCE,f] for f in m.f1) + sum(m.pRest[sCE,f] for f in m.fr)) for sCE in m.sCE ) + )) * 1e-3 + #M€ + d['EQ_UncCost_Cher'] = Constraint(m.sYear, rule = EQ_UncCost_Cher, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_UncCost_Cher2 (m, f1, sYear ): + return m.vBeta[f1,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-3* ( + 1e-3 * m.pYrGap * sum((m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) * (m.pAlpha_up[sPE,f1] - m.pAlpha_do[sPE,f1]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum( m.vCENewCap[sCE,sYear] * (m.pAlpha_up[sCE,f1] - m.pAlpha_do[sCE,f1]) for sCE in m.sCE ) + ) + #M€ + d['EQ_UncCost_Cher2'] = Constraint(m.f1,m.sYear, rule = EQ_UncCost_Cher2, doc = '') + + + def EQ_OpCost_Unc (m, sYear ): + return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e3 * sum(m.pCEFixom[sCE] * m.vCEActCap[sCE, sYear ] for sCE in m.sCE) + + 1e3 * sum(m.pRMCost [sRM,sYear] * m.vQSTInRM [sRM,sST,sES,sVin,sYear,sSeason,sDay,sHour] for (_,sRM,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTInRM_indexed[sYear]) + + 1e-3* sum(m.pSTFixom[sST ] * m.vSTTotCap[ sST, sVin,sYear ] for (_,sST,sVin) in m.sQSTVin_indexed[sYear]) + + 1e-3* sum(m.pSTVarom[sST,sES ] * (m.vQSTOut [ sST,sES,sVin,sYear,sSeason,sDay,sHour]) for (_,sST,sES,sVin,sSeason,sDay,sHour) in m.sQSTOUT_VinTime_indexed[sYear]) + #+ 1e3* m.pESNSCost * sum(m.vQESNS [sST,sES, sYear,sSeason,sDay,sHour] for (_,sST,sES,sSeason,sDay,sHour) in m.sQSTOUT_Time_indexed[sYear]) + + m.vOpVarom[sYear] + ) * 1e-3 + #M€ + d['EQ_OpCost_Unc'] = Constraint(m.sYear, rule = EQ_OpCost_Unc, doc = 'Annual Total Operation Cost [M€]') + + + def EQ_InvCostCE_Unc (m, sCE, sYear ): + return m.vInvCostCE[sCE,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( + m.pCEDecom[sCE,sYear] * m.vCEDecCap [sCE,sYear] + + m.pCEReact[sCE,sYear] * m.vCEDeltaActCap[sCE,sYear] + ) *1e-3 + #G€ + d['EQ_InvCostCE_Unc'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE_Unc, doc = 'Annual Total CE Investment Cost [G€]') + + + # RO Bertsimas + + def EQ_UncCost_Bert (m, sYear ): + return m.vUncCost[sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + # ) * 1e-3 + sum(m.vP[sUnc,sYear] for (sUnc,sYear) in m.sUnc*m.sYear) + m.vW * m.pTau + ) * 1e-3 + sum(m.vP[sUnc,sYear] for sUnc in m.sUnc) + m.vW * m.pTau + #M€ + d['EQ_UncCost_Bert'] = Constraint(m.sYear, rule = EQ_UncCost_Bert, doc = 'Annual Total Operation Cost [M€]') + + def EQ_UncCost_Bert2 (m, sUnc, sYear ): + return m.vW + m.vP[sUnc,sYear] >= (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( + 1e-3*m.pYrGap * sum(m.pDeltaUnc [sPE,sYear] * (m.vQPEImp [sPE,sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) + + sum(m.pDeltaUnc [sCE,sYear] * m.vCENewCap[sCE,sYear] for sCE in m.sCE ) + ) * 1e-3 + #M€ + d['EQ_UncCost_Bert2'] = Constraint(m.sUnc, m.sYear, rule = EQ_UncCost_Bert2, doc = 'Annual Total Operation Cost [M€]') + + # Objective function-related constraints @@ -488,13 +606,15 @@ def EQ_SysCost (m ): def EQ_PenalCost (m, sYear ): - return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * 1e-2* m.pESNSCost * ( + return m.vPenalCost [sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * m.pESNSCost * (( + (1-m.pEmiCO2CapSectRestr) * (1 - m.pEmiCO2BudgetRestr) * m.vEmiCO2CapExc [sYear] + m.pEmiCO2CapSectRestr * (1 - m.pEmiCO2BudgetRestr) * sum((m.vEmiCO2CapTraExc[sYear] + m.vEmiCO2CapEleExc[sYear] + m.vEmiCO2CapIndTEExc[sYear] + m.vEmiCO2CapIndProExc[sYear] + m.vEmiCO2CapOthExc[sYear] + m.vEmiCO2CapRefExc[sYear]) for sYear in m.sYear) + sum((m.vEmiNOxCapExc [sYear] + m.vEmiSOxCapExc [sYear] + m.vEmiPM25CapExc [sYear] ) for sYear in m.sYear) - ) + ) * 1e-2 + + m.pCECapExcess*sum(m.vCECapExc[sCE,sYear] for sCE in m.sCE) + + m.pSTCapExcess*sum(m.vSTCapExc[sST,sYear] for sST in m.sST)) #G€ - d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') + d['EQ_PenalCost'] = Constraint(m.sYear, rule = EQ_PenalCost, doc = 'Penalization Cost [G€]') def EQ_TotalCost (m, sYear ): @@ -534,6 +654,8 @@ def EQ_InvCostCE (m, sCE, sYear ): #G€ d['EQ_InvCostCE'] = Constraint(m.sCE, m.sYear, rule = EQ_InvCostCE, doc = 'Annual Total CE Investment Cost [G€]') + + def EQ_InvCostST (m, sST, sYear ): return m.vInvCostST[sST,sYear] == (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) * ( @@ -543,7 +665,8 @@ def EQ_InvCostST (m, sST, sYear ): #G€ d['EQ_InvCostST'] = Constraint(m.sST, m.sYear, rule = EQ_InvCostST, doc = 'Annual Total ST Investment Cost [G€]') - + + def EQ_OpCost (m, sYear ): return m.vOpCost[sYear] == m.pYrGap * (1/((1+m.pDisRate)**(m.pYrGap*(m.sYear.ord(sYear)-1)))) *( sum(m.pPECost [sPE,sYear] * (m.vQPEImp [sPE, sYear,sSeason,sDay,sHour] + m.vQPEDom[sPE,sYear,sSeason,sDay,sHour]) for (sPE,sSeason,sDay,sHour) in m.sPEYearTime) @@ -556,7 +679,9 @@ def EQ_OpCost (m, sYear ): ) * 1e-3 #M€ d['EQ_OpCost'] = Constraint(m.sYear, rule = EQ_OpCost, doc = 'Annual Total Operation Cost [M€]') + + def EQ_OpVarom (m, sYear ): return m.vOpVarom[sYear] == ( @@ -570,6 +695,9 @@ def EQ_OpVarom (m, sYear ): d['EQ_OpVarom'] = Constraint(m.sYear, rule = EQ_OpVarom, doc = 'Annual Total Varom Cost [k€]') + #Definition of a new equation including uncertain parameters (pCECost and pCECapex) + + # Primary energy (PE)-related constraints @@ -1186,6 +1314,19 @@ def EQ_CoalCap (m, sCE_Coal,sYear ): #GW d['EQ_CoalCap'] = Constraint(m.sCE_Coal,m.sYear, rule = EQ_CoalCap, doc = 'Coal phase-out restriction [GW]') + # CE limitations + + def EQ_CELimit (m, sCE,sYear ): + return m.pCEInsPathwayCap[sCE,sYear] >= m.vCETotCap[sCE,sYear] - m.vCECapExc [sCE,sYear] + #GW + d['EQ_CELimit'] = Constraint(m.sCE,m.sYear, rule = EQ_CELimit, doc = 'CE capacity limitations [GW]') + + # ST limitations + + def EQ_STLimit (m, sST,sYear ): + return m.pSTInsPathwayCap[sST,sYear] >= m.vSTNewCap[sST,sYear] - m.vSTCapExc [sST,sYear] + #GW + d['EQ_STLimit'] = Constraint(m.sST,m.sYear, rule = EQ_STLimit, doc = 'ST capacity limitations [GW]') # Supply Technologies (ST) capacity constraints @@ -1202,12 +1343,12 @@ def EQ_STMaxProUni (m, sST_Uni,sVin,sYear ): d['EQ_STMaxProUni'] = Constraint(m.sST_Uni,m.sVinYear, rule = EQ_STMaxProUni, doc = 'ST maximum production per unit [ES units]') - ''' - #def EQ_STMaxCap (m, sST,sYear ): - # return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) - #GW - #d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') - ''' + + def EQ_STMaxCap (m, sST,sYear ): + return m.pSTMaxCap [sST] >= sum(m.vSTTotCap [sST,sVin,sYear] for sVin in m.sVin if (sVin,sYear) in m.sVinYear) + # GW + d['EQ_STMaxCap'] = Constraint(m.sST,m.sYear, rule = EQ_STMaxCap, doc = 'ST maximum capacity [ST units]') + def EQ_STInsCap (m, sST,sVin,sYear ): @@ -1218,7 +1359,9 @@ def EQ_STInsCap (m, sST,sVin,sYear ): def EQ_STDecCap (m, sST,sVin, sYear ): return m.vSTDecCap [ sST,sVin, sYear ] == ( - ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if m.sAge.ord(sAge)==m.pYr[sYear]-m.pYr[sVin])) + ((m.vSTTotCap [ sST,sVin,m.sYear.prev(sYear)] if sYear>m.sYear.first() else (1-m.pGreenfield)*m.pSTInsCap[sST,sVin]) if m.pYr[sYear]>m.pYr[sVin] else 0) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)-1==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap)))) + # (m.vSTTotCap [ sST,sVin,sYear]) * sum(m.pSTDecProb[sST,sAge] for sAge in m.sAge if (m.sAge.ord(sAge)+1)==((m.pYr[sYear]-m.pYr[sVin])/m.pYrGap))) + #GW d['EQ_STDecCap'] = Constraint(m.sST,m.sVinYear, rule = EQ_STDecCap, doc = 'ST decommissioned capacity [ST units]') @@ -1585,6 +1728,19 @@ def EQ_EmiCO2CapRef (m, sYear ): d['EQ_EmiCO2CapRef'] = Constraint(m.sYear, rule = EQ_EmiCO2CapRef, doc = 'Refinery production emission cap restriction [MtCO2]') l_eq = [ + #'EQ_TotalCost_Unc', + + #'EQ_UncCost', + + #'EQ_UncCost_Cher', + #'EQ_UncCost_Cher2', + + #'EQ_UncCost_Bert', + #'EQ_UncCost_Bert2', + + #'EQ_InvCostCE_Unc', + #'EQ_OpCost_Unc', + 'EQ_FObj', 'EQ_SysCost', 'EQ_PenalCost', @@ -1630,15 +1786,15 @@ def EQ_EmiCO2CapRef (m, sYear ): 'EQ_MaxMS_UrbanRail', 'EQ_MaxMS_Air', 'EQ_MaxMS_Sea', - #'EQ_TC_Car', - #'EQ_TC_Moped', - #'EQ_TC_RoadFreight', - #'EQ_TC_Bus', - #'EQ_TC_UrbanRail', - #'EQ_TC_IntRail', - #'EQ_TC_Air', - #'EQ_TC_Sea', - #'EQ_TC_Oth', + # 'EQ_TC_Car', + # 'EQ_TC_Moped', + # 'EQ_TC_RoadFreight', + # 'EQ_TC_Bus', + # 'EQ_TC_UrbanRail', + # 'EQ_TC_IntRail', + # 'EQ_TC_Air', + # 'EQ_TC_Sea', + # 'EQ_TC_Oth', 'EQ_ESBalance', 'EQ_AFTra', 'EQ_BMTra', @@ -1656,7 +1812,7 @@ def EQ_EmiCO2CapRef (m, sYear ): 'EQ_STBalanceRM', 'EQ_AFInd', 'EQ_DCInd', - 'EQ_CircularityInd', + #'EQ_CircularityInd', 'EQ_CEMaxPro_Pri', 'EQ_CEMaxPro_Sec', 'EQ_CEMaxPro_Sto', @@ -1672,7 +1828,7 @@ def EQ_EmiCO2CapRef (m, sYear ): 'EQ_CoalCap', 'EQ_STMaxProCap', 'EQ_STMaxProUni', - #'EQ_STMaxCap', + # 'EQ_STMaxCap', 'EQ_STInsCap', 'EQ_STDecCap', 'EQ_EmiCO2CEPri', @@ -1692,7 +1848,7 @@ def EQ_EmiCO2CapRef (m, sYear ): 'EQ_EmiNOxSTTE', 'EQ_EmiNOxSTPro', 'EQ_EmiNOxST', - 'EQ_EmiNOxESNS', + #'EQ_EmiNOxESNS', 'EQ_EmiNOxTot', 'EQ_EmiSOxCEPri', 'EQ_EmiSOxCESec', @@ -1701,7 +1857,7 @@ def EQ_EmiCO2CapRef (m, sYear ): 'EQ_EmiSOxSTTE', 'EQ_EmiSOxSTPro', 'EQ_EmiSOxST', - 'EQ_EmiSOxESNS', + #'EQ_EmiSOxESNS', 'EQ_EmiSOxTot', 'EQ_EmiPM25CEPri', 'EQ_EmiPM25CESec', @@ -1710,19 +1866,21 @@ def EQ_EmiCO2CapRef (m, sYear ): 'EQ_EmiPM25STTE', 'EQ_EmiPM25STPro', 'EQ_EmiPM25ST', - 'EQ_EmiPM25ESNS', + #'EQ_EmiPM25ESNS', 'EQ_EmiPM25Tot', - 'EQ_EmiCO2Cap', + # 'EQ_EmiCO2Cap', 'EQ_EmiNOxCap', 'EQ_EmiSOxCap', 'EQ_EmiPM25Cap', - 'EQ_EmiCO2Budget', + # 'EQ_EmiCO2Budget', 'EQ_EmiCO2CapTra', - 'EQ_EmiCO2CapEle', - 'EQ_EmiCO2CapIndTE', - 'EQ_EmiCO2CapIndPro', + 'EQ_EmiCO2CapEle', # + 'EQ_EmiCO2CapIndTE', # + 'EQ_EmiCO2CapIndPro', # 'EQ_EmiCO2CapOth', - 'EQ_EmiCO2CapRef', + 'EQ_EmiCO2CapRef', # + 'EQ_CELimit', + 'EQ_STLimit', ] for eq in l_eq: setattr(m, eq, d[eq])